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