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