]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/comedi/drivers/adv_pci1710.c
82433864094ffea5395f25f0fa33104416a73133
[net-next-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 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->chanlist_len) {
1039                 cmd->chanlist_len = 1;
1040                 err++;
1041         }
1042         if (cmd->chanlist_len > this_board->n_aichan) {
1043                 cmd->chanlist_len = this_board->n_aichan;
1044                 err++;
1045         }
1046         if (cmd->scan_end_arg != cmd->chanlist_len) {
1047                 cmd->scan_end_arg = cmd->chanlist_len;
1048                 err++;
1049         }
1050         if (cmd->stop_src == TRIG_COUNT) {
1051                 if (!cmd->stop_arg) {
1052                         cmd->stop_arg = 1;
1053                         err++;
1054                 }
1055         } else {                /* TRIG_NONE */
1056                 if (cmd->stop_arg != 0) {
1057                         cmd->stop_arg = 0;
1058                         err++;
1059                 }
1060         }
1061
1062         if (err) {
1063 #ifdef PCI171X_EXTDEBUG
1064                 pci171x_cmdtest_out(3, cmd);
1065 #endif
1066                 DPRINTK
1067                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1068                      err);
1069                 return 3;
1070         }
1071
1072         /* step 4: fix up any arguments */
1073
1074         if (cmd->convert_src == TRIG_TIMER) {
1075                 tmp = cmd->convert_arg;
1076                 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1077                                           &divisor2, &cmd->convert_arg,
1078                                           cmd->flags & TRIG_ROUND_MASK);
1079                 if (cmd->convert_arg < this_board->ai_ns_min)
1080                         cmd->convert_arg = this_board->ai_ns_min;
1081                 if (tmp != cmd->convert_arg)
1082                         err++;
1083         }
1084
1085         if (err) {
1086                 DPRINTK
1087                     ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1088                      err);
1089                 return 4;
1090         }
1091
1092         /* step 5: complain about special chanlist considerations */
1093
1094         if (cmd->chanlist) {
1095                 if (!check_channel_list(dev, s, cmd->chanlist,
1096                                         cmd->chanlist_len))
1097                         return 5;       /*  incorrect channels list */
1098         }
1099
1100         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1101         return 0;
1102 }
1103
1104 /*
1105 ==============================================================================
1106 */
1107 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1108 {
1109         struct comedi_cmd *cmd = &s->async->cmd;
1110
1111         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1112         devpriv->ai_n_chan = cmd->chanlist_len;
1113         devpriv->ai_chanlist = cmd->chanlist;
1114         devpriv->ai_flags = cmd->flags;
1115         devpriv->ai_data_len = s->async->prealloc_bufsz;
1116         devpriv->ai_data = s->async->prealloc_buf;
1117         devpriv->ai_timer1 = 0;
1118         devpriv->ai_timer2 = 0;
1119
1120         if (cmd->stop_src == TRIG_COUNT) {
1121                 devpriv->ai_scans = cmd->stop_arg;
1122         } else {
1123                 devpriv->ai_scans = 0;
1124         }
1125
1126         if (cmd->scan_begin_src == TRIG_FOLLOW) {       /*  mode 1, 2, 3 */
1127                 if (cmd->convert_src == TRIG_TIMER) {   /*  mode 1 and 2 */
1128                         devpriv->ai_timer1 = cmd->convert_arg;
1129                         return pci171x_ai_docmd_and_mode(cmd->start_src ==
1130                                                          TRIG_EXT ? 2 : 1, dev,
1131                                                          s);
1132                 }
1133                 if (cmd->convert_src == TRIG_EXT) {     /*  mode 3 */
1134                         return pci171x_ai_docmd_and_mode(3, dev, s);
1135                 }
1136         }
1137
1138         return -1;
1139 }
1140
1141 /*
1142 ==============================================================================
1143  Check if channel list from user is builded correctly
1144  If it's ok, then program scan/gain logic.
1145  This works for all cards.
1146 */
1147 static int check_channel_list(struct comedi_device *dev,
1148                               struct comedi_subdevice *s,
1149                               unsigned int *chanlist, unsigned int n_chan)
1150 {
1151         unsigned int chansegment[32];
1152         unsigned int i, nowmustbechan, seglen, segpos;
1153
1154         DPRINTK("adv_pci1710 EDBG:  check_channel_list(...,%d)\n", n_chan);
1155         /* correct channel and range number check itself comedi/range.c */
1156         if (n_chan < 1) {
1157                 comedi_error(dev, "range/channel list is empty!");
1158                 return 0;
1159         }
1160
1161         if (n_chan > 1) {
1162                 chansegment[0] = chanlist[0];   /*  first channel is everytime ok */
1163                 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {    /*  build part of chanlist */
1164                         /*  printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1165                         if (chanlist[0] == chanlist[i])
1166                                 break;  /*  we detect loop, this must by finish */
1167                         if (CR_CHAN(chanlist[i]) & 1)   /*  odd channel cann't by differencial */
1168                                 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1169                                         comedi_error(dev,
1170                                                      "Odd channel can't be differential input!\n");
1171                                         return 0;
1172                                 }
1173                         nowmustbechan =
1174                             (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1175                         if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1176                                 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1177                         if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continous :-( */
1178                                 printk
1179                                     ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1180                                      i, CR_CHAN(chanlist[i]), nowmustbechan,
1181                                      CR_CHAN(chanlist[0]));
1182                                 return 0;
1183                         }
1184                         chansegment[i] = chanlist[i];   /*  well, this is next correct channel in list */
1185                 }
1186
1187                 for (i = 0, segpos = 0; i < n_chan; i++) {      /*  check whole chanlist */
1188                         /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1189                         if (chanlist[i] != chansegment[i % seglen]) {
1190                                 printk
1191                                     ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1192                                      i, CR_CHAN(chansegment[i]),
1193                                      CR_RANGE(chansegment[i]),
1194                                      CR_AREF(chansegment[i]),
1195                                      CR_CHAN(chanlist[i % seglen]),
1196                                      CR_RANGE(chanlist[i % seglen]),
1197                                      CR_AREF(chansegment[i % seglen]));
1198                                 return 0;       /*  chan/gain list is strange */
1199                         }
1200                 }
1201         } else {
1202                 seglen = 1;
1203         }
1204         return seglen;
1205 }
1206
1207 static void setup_channel_list(struct comedi_device *dev,
1208                                struct comedi_subdevice *s,
1209                                unsigned int *chanlist, unsigned int n_chan,
1210                                unsigned int seglen)
1211 {
1212         unsigned int i, range, chanprog;
1213
1214         DPRINTK("adv_pci1710 EDBG:  setup_channel_list(...,%d,%d)\n", n_chan,
1215                 seglen);
1216         devpriv->act_chanlist_len = seglen;
1217         devpriv->act_chanlist_pos = 0;
1218
1219         DPRINTK("SegLen: %d\n", seglen);
1220         for (i = 0; i < seglen; i++) {  /*  store range list to card */
1221                 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1222                 outw(chanprog, dev->iobase + PCI171x_MUX);      /* select channel */
1223                 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1224                 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1225                         range |= 0x0020;
1226                 outw(range, dev->iobase + PCI171x_RANGE);       /* select gain */
1227 #ifdef PCI171x_PARANOIDCHECK
1228                 devpriv->act_chanlist[i] =
1229                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1230 #endif
1231                 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1232                         devpriv->act_chanlist[i]);
1233         }
1234 #ifdef PCI171x_PARANOIDCHECK
1235         for ( ; i < n_chan; i++) { /* store remainder of channel list */
1236                 devpriv->act_chanlist[i] =
1237                     (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1238         }
1239 #endif
1240
1241         devpriv->ai_et_MuxVal =
1242             CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1243         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
1244         DPRINTK("MUX: %4x L%4x.H%4x\n",
1245                 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1246                 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1247 }
1248
1249 /*
1250 ==============================================================================
1251 */
1252 static void start_pacer(struct comedi_device *dev, int mode,
1253                         unsigned int divisor1, unsigned int divisor2)
1254 {
1255         DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1256                 divisor1, divisor2);
1257         outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1258         outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1259
1260         if (mode == 1) {
1261                 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1262                 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1263                 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1264                 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1265         }
1266         DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1267 }
1268
1269 /*
1270 ==============================================================================
1271 */
1272 static int pci171x_ai_cancel(struct comedi_device *dev,
1273                              struct comedi_subdevice *s)
1274 {
1275         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1276
1277         switch (this_board->cardtype) {
1278         default:
1279                 devpriv->CntrlReg &= Control_CNT0;
1280                 devpriv->CntrlReg |= Control_SW;
1281
1282                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1283                 start_pacer(dev, -1, 0, 0);
1284                 outb(0, dev->iobase + PCI171x_CLRFIFO);
1285                 outb(0, dev->iobase + PCI171x_CLRINT);
1286                 break;
1287         }
1288
1289         devpriv->ai_do = 0;
1290         devpriv->ai_act_scan = 0;
1291         s->async->cur_chan = 0;
1292         devpriv->ai_buf_ptr = 0;
1293         devpriv->neverending_ai = 0;
1294
1295         DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1296         return 0;
1297 }
1298
1299 /*
1300 ==============================================================================
1301 */
1302 static int pci171x_reset(struct comedi_device *dev)
1303 {
1304         DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1305         outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1306         devpriv->CntrlReg = Control_SW | Control_CNT0;  /*  Software trigger, CNT0=external */
1307         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /*  reset any operations */
1308         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1309         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1310         start_pacer(dev, -1, 0, 0);     /*  stop 8254 */
1311         devpriv->da_ranges = 0;
1312         if (this_board->n_aochan) {
1313                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);  /*  set DACs to 0..5V */
1314                 outw(0, dev->iobase + PCI171x_DA1);     /*  set DA outputs to 0V */
1315                 devpriv->ao_data[0] = 0x0000;
1316                 if (this_board->n_aochan > 1) {
1317                         outw(0, dev->iobase + PCI171x_DA2);
1318                         devpriv->ao_data[1] = 0x0000;
1319                 }
1320         }
1321         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
1322         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
1323         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
1324
1325         DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1326         return 0;
1327 }
1328
1329 /*
1330 ==============================================================================
1331 */
1332 static int pci1720_reset(struct comedi_device *dev)
1333 {
1334         DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1335         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);       /*  set synchronous output mode */
1336         devpriv->da_ranges = 0xAA;
1337         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);  /*  set all ranges to +/-5V */
1338         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
1339         outw(0x0800, dev->iobase + PCI1720_DA1);
1340         outw(0x0800, dev->iobase + PCI1720_DA2);
1341         outw(0x0800, dev->iobase + PCI1720_DA3);
1342         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
1343         devpriv->ao_data[0] = 0x0800;
1344         devpriv->ao_data[1] = 0x0800;
1345         devpriv->ao_data[2] = 0x0800;
1346         devpriv->ao_data[3] = 0x0800;
1347         DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1348         return 0;
1349 }
1350
1351 /*
1352 ==============================================================================
1353 */
1354 static int pci1710_reset(struct comedi_device *dev)
1355 {
1356         DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1357         switch (this_board->cardtype) {
1358         case TYPE_PCI1720:
1359                 return pci1720_reset(dev);
1360         default:
1361                 return pci171x_reset(dev);
1362         }
1363         DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1364 }
1365
1366 /*
1367 ==============================================================================
1368 */
1369 static int pci1710_attach(struct comedi_device *dev,
1370                           struct comedi_devconfig *it)
1371 {
1372         struct comedi_subdevice *s;
1373         int ret, subdev, n_subdevices;
1374         unsigned int irq;
1375         unsigned long iobase;
1376         struct pci_dev *pcidev;
1377         int opt_bus, opt_slot;
1378         const char *errstr;
1379         unsigned char pci_bus, pci_slot, pci_func;
1380         int i;
1381         int board_index;
1382
1383         printk("comedi%d: adv_pci1710: ", dev->minor);
1384
1385         opt_bus = it->options[0];
1386         opt_slot = it->options[1];
1387
1388         ret = alloc_private(dev, sizeof(struct pci1710_private));
1389         if (ret < 0) {
1390                 printk(" - Allocation failed!\n");
1391                 return -ENOMEM;
1392         }
1393
1394         /* Look for matching PCI device */
1395         errstr = "not found!";
1396         pcidev = NULL;
1397         board_index = this_board - boardtypes;
1398         while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1399                                                 PCI_ANY_ID, pcidev))) {
1400                 if (strcmp(this_board->name, DRV_NAME) == 0) {
1401                         for (i = 0; i < n_boardtypes; ++i) {
1402                                 if (pcidev->device == boardtypes[i].device_id) {
1403                                         board_index = i;
1404                                         break;
1405                                 }
1406                         }
1407                         if (i == n_boardtypes)
1408                                 continue;
1409                 } else {
1410                         if (pcidev->device != boardtypes[board_index].device_id)
1411                                 continue;
1412                 }
1413
1414                 /* Found matching vendor/device. */
1415                 if (opt_bus || opt_slot) {
1416                         /* Check bus/slot. */
1417                         if (opt_bus != pcidev->bus->number
1418                             || opt_slot != PCI_SLOT(pcidev->devfn))
1419                                 continue;       /* no match */
1420                 }
1421                 /*
1422                  * Look for device that isn't in use.
1423                  * Enable PCI device and request regions.
1424                  */
1425                 if (comedi_pci_enable(pcidev, DRV_NAME)) {
1426                         errstr =
1427                             "failed to enable PCI device and request regions!";
1428                         continue;
1429                 }
1430                 /*  fixup board_ptr in case we were using the dummy entry with the driver name */
1431                 dev->board_ptr = &boardtypes[board_index];
1432                 break;
1433         }
1434
1435         if (!pcidev) {
1436                 if (opt_bus || opt_slot) {
1437                         printk(" - Card at b:s %d:%d %s\n",
1438                                opt_bus, opt_slot, errstr);
1439                 } else {
1440                         printk(" - Card %s\n", errstr);
1441                 }
1442                 return -EIO;
1443         }
1444
1445         pci_bus = pcidev->bus->number;
1446         pci_slot = PCI_SLOT(pcidev->devfn);
1447         pci_func = PCI_FUNC(pcidev->devfn);
1448         irq = pcidev->irq;
1449         iobase = pci_resource_start(pcidev, 2);
1450
1451         printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
1452                iobase);
1453
1454         dev->iobase = iobase;
1455
1456         dev->board_name = this_board->name;
1457         devpriv->pcidev = pcidev;
1458
1459         n_subdevices = 0;
1460         if (this_board->n_aichan)
1461                 n_subdevices++;
1462         if (this_board->n_aochan)
1463                 n_subdevices++;
1464         if (this_board->n_dichan)
1465                 n_subdevices++;
1466         if (this_board->n_dochan)
1467                 n_subdevices++;
1468         if (this_board->n_counter)
1469                 n_subdevices++;
1470
1471         ret = alloc_subdevices(dev, n_subdevices);
1472         if (ret < 0) {
1473                 printk(" - Allocation failed!\n");
1474                 return ret;
1475         }
1476
1477         pci1710_reset(dev);
1478
1479         if (this_board->have_irq) {
1480                 if (irq) {
1481                         if (request_irq(irq, interrupt_service_pci1710,
1482                                         IRQF_SHARED, "Advantech PCI-1710",
1483                                         dev)) {
1484                                 printk
1485                                     (", unable to allocate IRQ %d, DISABLING IT",
1486                                      irq);
1487                                 irq = 0;        /* Can't use IRQ */
1488                         } else {
1489                                 printk(", irq=%u", irq);
1490                         }
1491                 } else {
1492                         printk(", IRQ disabled");
1493                 }
1494         } else {
1495                 irq = 0;
1496         }
1497
1498         dev->irq = irq;
1499
1500         printk(".\n");
1501
1502         subdev = 0;
1503
1504         if (this_board->n_aichan) {
1505                 s = dev->subdevices + subdev;
1506                 dev->read_subdev = s;
1507                 s->type = COMEDI_SUBD_AI;
1508                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1509                 if (this_board->n_aichand)
1510                         s->subdev_flags |= SDF_DIFF;
1511                 s->n_chan = this_board->n_aichan;
1512                 s->maxdata = this_board->ai_maxdata;
1513                 s->len_chanlist = this_board->n_aichan;
1514                 s->range_table = this_board->rangelist_ai;
1515                 s->cancel = pci171x_ai_cancel;
1516                 s->insn_read = pci171x_insn_read_ai;
1517                 if (irq) {
1518                         s->subdev_flags |= SDF_CMD_READ;
1519                         s->do_cmdtest = pci171x_ai_cmdtest;
1520                         s->do_cmd = pci171x_ai_cmd;
1521                 }
1522                 devpriv->i8254_osc_base = 100;  /*  100ns=10MHz */
1523                 subdev++;
1524         }
1525
1526         if (this_board->n_aochan) {
1527                 s = dev->subdevices + subdev;
1528                 s->type = COMEDI_SUBD_AO;
1529                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1530                 s->n_chan = this_board->n_aochan;
1531                 s->maxdata = this_board->ao_maxdata;
1532                 s->len_chanlist = this_board->n_aochan;
1533                 s->range_table = this_board->rangelist_ao;
1534                 switch (this_board->cardtype) {
1535                 case TYPE_PCI1720:
1536                         s->insn_write = pci1720_insn_write_ao;
1537                         break;
1538                 default:
1539                         s->insn_write = pci171x_insn_write_ao;
1540                         break;
1541                 }
1542                 s->insn_read = pci171x_insn_read_ao;
1543                 subdev++;
1544         }
1545
1546         if (this_board->n_dichan) {
1547                 s = dev->subdevices + subdev;
1548                 s->type = COMEDI_SUBD_DI;
1549                 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1550                 s->n_chan = this_board->n_dichan;
1551                 s->maxdata = 1;
1552                 s->len_chanlist = this_board->n_dichan;
1553                 s->range_table = &range_digital;
1554                 s->io_bits = 0; /* all bits input */
1555                 s->insn_bits = pci171x_insn_bits_di;
1556                 subdev++;
1557         }
1558
1559         if (this_board->n_dochan) {
1560                 s = dev->subdevices + subdev;
1561                 s->type = COMEDI_SUBD_DO;
1562                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1563                 s->n_chan = this_board->n_dochan;
1564                 s->maxdata = 1;
1565                 s->len_chanlist = this_board->n_dochan;
1566                 s->range_table = &range_digital;
1567                 s->io_bits = (1 << this_board->n_dochan) - 1;   /* all bits output */
1568                 s->state = 0;
1569                 s->insn_bits = pci171x_insn_bits_do;
1570                 subdev++;
1571         }
1572
1573         if (this_board->n_counter) {
1574                 s = dev->subdevices + subdev;
1575                 s->type = COMEDI_SUBD_COUNTER;
1576                 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1577                 s->n_chan = this_board->n_counter;
1578                 s->len_chanlist = this_board->n_counter;
1579                 s->maxdata = 0xffff;
1580                 s->range_table = &range_unknown;
1581                 s->insn_read = pci171x_insn_counter_read;
1582                 s->insn_write = pci171x_insn_counter_write;
1583                 s->insn_config = pci171x_insn_counter_config;
1584                 subdev++;
1585         }
1586
1587         devpriv->valid = 1;
1588
1589         return 0;
1590 }
1591
1592 /*
1593 ==============================================================================
1594 */
1595 static int pci1710_detach(struct comedi_device *dev)
1596 {
1597
1598         if (dev->private) {
1599                 if (devpriv->valid)
1600                         pci1710_reset(dev);
1601                 if (dev->irq)
1602                         free_irq(dev->irq, dev);
1603                 if (devpriv->pcidev) {
1604                         if (dev->iobase) {
1605                                 comedi_pci_disable(devpriv->pcidev);
1606                         }
1607                         pci_dev_put(devpriv->pcidev);
1608                 }
1609         }
1610
1611         return 0;
1612 }
1613
1614 /*
1615 ==============================================================================
1616 */
1617 COMEDI_PCI_INITCLEANUP(driver_pci1710, pci1710_pci_table);
1618 /*
1619 ==============================================================================
1620 */