Version:  2.0.40 2.2.26 2.4.37 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us