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