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