Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 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

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

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