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