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