Version:  2.0.40 2.2.26 2.4.37 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 3.19 4.0 4.1

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 information.
  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/interrupt.h>
 46 
 47 #include "../comedi_pci.h"
 48 
 49 #include "comedi_8254.h"
 50 #include "amcc_s5933.h"
 51 
 52 #define PCI171x_AD_DATA  0      /* R:   A/D data */
 53 #define PCI171x_SOFTTRG  0      /* W:   soft trigger for A/D */
 54 #define PCI171x_RANGE    2      /* W:   A/D gain/range register */
 55 #define PCI171x_MUX      4      /* W:   A/D multiplexor control */
 56 #define PCI171x_STATUS   6      /* R:   status register */
 57 #define PCI171x_CONTROL  6      /* W:   control register */
 58 #define PCI171x_CLRINT   8      /* W:   clear interrupts request */
 59 #define PCI171x_CLRFIFO  9      /* W:   clear FIFO */
 60 #define PCI171x_DA1     10      /* W:   D/A register */
 61 #define PCI171x_DA2     12      /* W:   D/A register */
 62 #define PCI171x_DAREF   14      /* W:   D/A reference control */
 63 #define PCI171x_DI      16      /* R:   digi inputs */
 64 #define PCI171x_DO      16      /* R:   digi inputs */
 65 
 66 #define PCI171X_TIMER_BASE      0x18
 67 
 68 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
 69  * reg) */
 70 #define Status_FE       0x0100  /* 1=FIFO is empty */
 71 #define Status_FH       0x0200  /* 1=FIFO is half full */
 72 #define Status_FF       0x0400  /* 1=FIFO is full, fatal error */
 73 #define Status_IRQ      0x0800  /* 1=IRQ occurred */
 74 /* bits from control register (PCI171x_CONTROL) */
 75 #define Control_CNT0    0x0040  /* 1=CNT0 have external source,
 76                                  * 0=have internal 100kHz source */
 77 #define Control_ONEFH   0x0020  /* 1=IRQ on FIFO is half full, 0=every sample */
 78 #define Control_IRQEN   0x0010  /* 1=enable IRQ */
 79 #define Control_GATE    0x0008  /* 1=enable external trigger GATE (8254?) */
 80 #define Control_EXT     0x0004  /* 1=external trigger source */
 81 #define Control_PACER   0x0002  /* 1=enable internal 8254 trigger source */
 82 #define Control_SW      0x0001  /* 1=enable software trigger source */
 83 
 84 #define PCI1720_DA0      0      /* W:   D/A register 0 */
 85 #define PCI1720_DA1      2      /* W:   D/A register 1 */
 86 #define PCI1720_DA2      4      /* W:   D/A register 2 */
 87 #define PCI1720_DA3      6      /* W:   D/A register 3 */
 88 #define PCI1720_RANGE    8      /* R/W: D/A range register */
 89 #define PCI1720_SYNCOUT  9      /* W:   D/A synchronized output register */
 90 #define PCI1720_SYNCONT 15      /* R/W: D/A synchronized control */
 91 
 92 /* D/A synchronized control (PCI1720_SYNCONT) */
 93 #define Syncont_SC0      1      /* set synchronous output mode */
 94 
 95 static const struct comedi_lrange range_pci1710_3 = {
 96         9, {
 97                 BIP_RANGE(5),
 98                 BIP_RANGE(2.5),
 99                 BIP_RANGE(1.25),
100                 BIP_RANGE(0.625),
101                 BIP_RANGE(10),
102                 UNI_RANGE(10),
103                 UNI_RANGE(5),
104                 UNI_RANGE(2.5),
105                 UNI_RANGE(1.25)
106         }
107 };
108 
109 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
110                                               0x10, 0x11, 0x12, 0x13 };
111 
112 static const struct comedi_lrange range_pci1710hg = {
113         12, {
114                 BIP_RANGE(5),
115                 BIP_RANGE(0.5),
116                 BIP_RANGE(0.05),
117                 BIP_RANGE(0.005),
118                 BIP_RANGE(10),
119                 BIP_RANGE(1),
120                 BIP_RANGE(0.1),
121                 BIP_RANGE(0.01),
122                 UNI_RANGE(10),
123                 UNI_RANGE(1),
124                 UNI_RANGE(0.1),
125                 UNI_RANGE(0.01)
126         }
127 };
128 
129 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
130                                               0x05, 0x06, 0x07, 0x10, 0x11,
131                                               0x12, 0x13 };
132 
133 static const struct comedi_lrange range_pci17x1 = {
134         5, {
135                 BIP_RANGE(10),
136                 BIP_RANGE(5),
137                 BIP_RANGE(2.5),
138                 BIP_RANGE(1.25),
139                 BIP_RANGE(0.625)
140         }
141 };
142 
143 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
144 
145 static const struct comedi_lrange pci1720_ao_range = {
146         4, {
147                 UNI_RANGE(5),
148                 UNI_RANGE(10),
149                 BIP_RANGE(5),
150                 BIP_RANGE(10)
151         }
152 };
153 
154 static const struct comedi_lrange pci171x_ao_range = {
155         2, {
156                 UNI_RANGE(5),
157                 UNI_RANGE(10)
158         }
159 };
160 
161 enum pci1710_boardid {
162         BOARD_PCI1710,
163         BOARD_PCI1710HG,
164         BOARD_PCI1711,
165         BOARD_PCI1713,
166         BOARD_PCI1720,
167         BOARD_PCI1731,
168 };
169 
170 struct boardtype {
171         const char *name;       /*  board name */
172         int n_aichan;           /*  num of A/D chans */
173         const struct comedi_lrange *rangelist_ai;       /*  rangelist for A/D */
174         const char *rangecode_ai;       /*  range codes for programming */
175         unsigned int is_pci1713:1;
176         unsigned int is_pci1720:1;
177         unsigned int has_irq:1;
178         unsigned int has_large_fifo:1;  /* 4K or 1K FIFO */
179         unsigned int has_diff_ai:1;
180         unsigned int has_ao:1;
181         unsigned int has_di_do:1;
182         unsigned int has_counter:1;
183 };
184 
185 static const struct boardtype boardtypes[] = {
186         [BOARD_PCI1710] = {
187                 .name           = "pci1710",
188                 .n_aichan       = 16,
189                 .rangelist_ai   = &range_pci1710_3,
190                 .rangecode_ai   = range_codes_pci1710_3,
191                 .has_irq        = 1,
192                 .has_large_fifo = 1,
193                 .has_diff_ai    = 1,
194                 .has_ao         = 1,
195                 .has_di_do      = 1,
196                 .has_counter    = 1,
197         },
198         [BOARD_PCI1710HG] = {
199                 .name           = "pci1710hg",
200                 .n_aichan       = 16,
201                 .rangelist_ai   = &range_pci1710hg,
202                 .rangecode_ai   = range_codes_pci1710hg,
203                 .has_irq        = 1,
204                 .has_large_fifo = 1,
205                 .has_diff_ai    = 1,
206                 .has_ao         = 1,
207                 .has_di_do      = 1,
208                 .has_counter    = 1,
209         },
210         [BOARD_PCI1711] = {
211                 .name           = "pci1711",
212                 .n_aichan       = 16,
213                 .rangelist_ai   = &range_pci17x1,
214                 .rangecode_ai   = range_codes_pci17x1,
215                 .has_irq        = 1,
216                 .has_ao         = 1,
217                 .has_di_do      = 1,
218                 .has_counter    = 1,
219         },
220         [BOARD_PCI1713] = {
221                 .name           = "pci1713",
222                 .n_aichan       = 32,
223                 .rangelist_ai   = &range_pci1710_3,
224                 .rangecode_ai   = range_codes_pci1710_3,
225                 .is_pci1713     = 1,
226                 .has_irq        = 1,
227                 .has_large_fifo = 1,
228                 .has_diff_ai    = 1,
229         },
230         [BOARD_PCI1720] = {
231                 .name           = "pci1720",
232                 .is_pci1720     = 1,
233                 .has_ao         = 1,
234         },
235         [BOARD_PCI1731] = {
236                 .name           = "pci1731",
237                 .n_aichan       = 16,
238                 .rangelist_ai   = &range_pci17x1,
239                 .rangecode_ai   = range_codes_pci17x1,
240                 .has_irq        = 1,
241                 .has_di_do      = 1,
242         },
243 };
244 
245 struct pci1710_private {
246         unsigned int max_samples;
247         unsigned int CntrlReg;  /*  Control register */
248         unsigned char ai_et;
249         unsigned int ai_et_CntrlReg;
250         unsigned int ai_et_MuxVal;
251         unsigned int act_chanlist[32];  /*  list of scanned channel */
252         unsigned char saved_seglen;     /* len of the non-repeating chanlist */
253         unsigned char da_ranges;        /*  copy of D/A outpit range register */
254 };
255 
256 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
257                                      struct comedi_subdevice *s,
258                                      struct comedi_cmd *cmd)
259 {
260         struct pci1710_private *devpriv = dev->private;
261         unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
262         unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
263         unsigned int next_chan = (chan0 + 1) % s->n_chan;
264         unsigned int chansegment[32];
265         unsigned int seglen;
266         int i;
267 
268         if (cmd->chanlist_len == 1) {
269                 devpriv->saved_seglen = cmd->chanlist_len;
270                 return 0;
271         }
272 
273         /* first channel is always ok */
274         chansegment[0] = cmd->chanlist[0];
275 
276         for (i = 1; i < cmd->chanlist_len; i++) {
277                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
278                 unsigned int aref = CR_AREF(cmd->chanlist[i]);
279 
280                 if (cmd->chanlist[0] == cmd->chanlist[i])
281                         break;  /*  we detected a loop, stop */
282 
283                 if (aref == AREF_DIFF && (chan & 1)) {
284                         dev_err(dev->class_dev,
285                                 "Odd channel cannot be differential input!\n");
286                         return -EINVAL;
287                 }
288 
289                 if (last_aref == AREF_DIFF)
290                         next_chan = (next_chan + 1) % s->n_chan;
291                 if (chan != next_chan) {
292                         dev_err(dev->class_dev,
293                                 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
294                                 i, chan, next_chan, chan0);
295                         return -EINVAL;
296                 }
297 
298                 /* next correct channel in list */
299                 chansegment[i] = cmd->chanlist[i];
300                 last_aref = aref;
301         }
302         seglen = i;
303 
304         for (i = 0; i < cmd->chanlist_len; i++) {
305                 if (cmd->chanlist[i] != chansegment[i % seglen]) {
306                         dev_err(dev->class_dev,
307                                 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
308                                 i, CR_CHAN(chansegment[i]),
309                                 CR_RANGE(chansegment[i]),
310                                 CR_AREF(chansegment[i]),
311                                 CR_CHAN(cmd->chanlist[i % seglen]),
312                                 CR_RANGE(cmd->chanlist[i % seglen]),
313                                 CR_AREF(chansegment[i % seglen]));
314                         return -EINVAL;
315                 }
316         }
317         devpriv->saved_seglen = seglen;
318 
319         return 0;
320 }
321 
322 static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
323                                       struct comedi_subdevice *s,
324                                       unsigned int *chanlist,
325                                       unsigned int n_chan,
326                                       unsigned int seglen)
327 {
328         const struct boardtype *board = dev->board_ptr;
329         struct pci1710_private *devpriv = dev->private;
330         unsigned int first_chan = CR_CHAN(chanlist[0]);
331         unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
332         unsigned int i;
333 
334         for (i = 0; i < seglen; i++) {  /*  store range list to card */
335                 unsigned int chan = CR_CHAN(chanlist[i]);
336                 unsigned int range = CR_RANGE(chanlist[i]);
337                 unsigned int aref = CR_AREF(chanlist[i]);
338                 unsigned int rangeval;
339 
340                 rangeval = board->rangecode_ai[range];
341                 if (aref == AREF_DIFF)
342                         rangeval |= 0x0020;
343 
344                 /* select channel and set range */
345                 outw(chan | (chan << 8), dev->iobase + PCI171x_MUX);
346                 outw(rangeval, dev->iobase + PCI171x_RANGE);
347 
348                 devpriv->act_chanlist[i] = chan;
349         }
350         for ( ; i < n_chan; i++)        /* store remainder of channel list */
351                 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
352 
353         /* select channel interval to scan */
354         devpriv->ai_et_MuxVal = first_chan | (last_chan << 8);
355         outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
356 }
357 
358 static int pci171x_ai_eoc(struct comedi_device *dev,
359                           struct comedi_subdevice *s,
360                           struct comedi_insn *insn,
361                           unsigned long context)
362 {
363         unsigned int status;
364 
365         status = inw(dev->iobase + PCI171x_STATUS);
366         if ((status & Status_FE) == 0)
367                 return 0;
368         return -EBUSY;
369 }
370 
371 static int pci171x_ai_read_sample(struct comedi_device *dev,
372                                   struct comedi_subdevice *s,
373                                   unsigned int cur_chan,
374                                   unsigned int *val)
375 {
376         const struct boardtype *board = dev->board_ptr;
377         struct pci1710_private *devpriv = dev->private;
378         unsigned int sample;
379         unsigned int chan;
380 
381         sample = inw(dev->iobase + PCI171x_AD_DATA);
382         if (!board->is_pci1713) {
383                 /*
384                  * The upper 4 bits of the 16-bit sample are the channel number
385                  * that the sample was acquired from. Verify that this channel
386                  * number matches the expected channel number.
387                  */
388                 chan = sample >> 12;
389                 if (chan != devpriv->act_chanlist[cur_chan]) {
390                         dev_err(dev->class_dev,
391                                 "A/D data droput: received from channel %d, expected %d\n",
392                                 chan, devpriv->act_chanlist[cur_chan]);
393                         return -ENODATA;
394                 }
395         }
396         *val = sample & s->maxdata;
397         return 0;
398 }
399 
400 static int pci171x_ai_insn_read(struct comedi_device *dev,
401                                 struct comedi_subdevice *s,
402                                 struct comedi_insn *insn,
403                                 unsigned int *data)
404 {
405         struct pci1710_private *devpriv = dev->private;
406         int ret = 0;
407         int i;
408 
409         devpriv->CntrlReg &= Control_CNT0;
410         devpriv->CntrlReg |= Control_SW;        /*  set software trigger */
411         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
412         outb(0, dev->iobase + PCI171x_CLRFIFO);
413         outb(0, dev->iobase + PCI171x_CLRINT);
414 
415         pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
416 
417         for (i = 0; i < insn->n; i++) {
418                 unsigned int val;
419 
420                 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
421 
422                 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
423                 if (ret)
424                         break;
425 
426                 ret = pci171x_ai_read_sample(dev, s, 0, &val);
427                 if (ret)
428                         break;
429 
430                 data[i] = val;
431         }
432 
433         outb(0, dev->iobase + PCI171x_CLRFIFO);
434         outb(0, dev->iobase + PCI171x_CLRINT);
435 
436         return ret ? ret : insn->n;
437 }
438 
439 static int pci171x_ao_insn_write(struct comedi_device *dev,
440                                  struct comedi_subdevice *s,
441                                  struct comedi_insn *insn,
442                                  unsigned int *data)
443 {
444         struct pci1710_private *devpriv = dev->private;
445         unsigned int chan = CR_CHAN(insn->chanspec);
446         unsigned int range = CR_RANGE(insn->chanspec);
447         unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
448         unsigned int val = s->readback[chan];
449         int i;
450 
451         devpriv->da_ranges &= ~(1 << (chan << 1));
452         devpriv->da_ranges |= (range << (chan << 1));
453         outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
454 
455         for (i = 0; i < insn->n; i++) {
456                 val = data[i];
457                 outw(val, dev->iobase + reg);
458         }
459 
460         s->readback[chan] = val;
461 
462         return insn->n;
463 }
464 
465 static int pci171x_di_insn_bits(struct comedi_device *dev,
466                                 struct comedi_subdevice *s,
467                                 struct comedi_insn *insn,
468                                 unsigned int *data)
469 {
470         data[1] = inw(dev->iobase + PCI171x_DI);
471 
472         return insn->n;
473 }
474 
475 static int pci171x_do_insn_bits(struct comedi_device *dev,
476                                 struct comedi_subdevice *s,
477                                 struct comedi_insn *insn,
478                                 unsigned int *data)
479 {
480         if (comedi_dio_update_state(s, data))
481                 outw(s->state, dev->iobase + PCI171x_DO);
482 
483         data[1] = s->state;
484 
485         return insn->n;
486 }
487 
488 static int pci1720_ao_insn_write(struct comedi_device *dev,
489                                  struct comedi_subdevice *s,
490                                  struct comedi_insn *insn,
491                                  unsigned int *data)
492 {
493         struct pci1710_private *devpriv = dev->private;
494         unsigned int chan = CR_CHAN(insn->chanspec);
495         unsigned int range = CR_RANGE(insn->chanspec);
496         unsigned int val;
497         int i;
498 
499         val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
500         val |= (range << (chan << 1));
501         if (val != devpriv->da_ranges) {
502                 outb(val, dev->iobase + PCI1720_RANGE);
503                 devpriv->da_ranges = val;
504         }
505 
506         val = s->readback[chan];
507         for (i = 0; i < insn->n; i++) {
508                 val = data[i];
509                 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
510                 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
511         }
512 
513         s->readback[chan] = val;
514 
515         return insn->n;
516 }
517 
518 static int pci171x_ai_cancel(struct comedi_device *dev,
519                              struct comedi_subdevice *s)
520 {
521         struct pci1710_private *devpriv = dev->private;
522 
523         devpriv->CntrlReg &= Control_CNT0;
524         devpriv->CntrlReg |= Control_SW;
525         /* reset any operations */
526         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
527         comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
528         outb(0, dev->iobase + PCI171x_CLRFIFO);
529         outb(0, dev->iobase + PCI171x_CLRINT);
530 
531         return 0;
532 }
533 
534 static void pci1710_handle_every_sample(struct comedi_device *dev,
535                                         struct comedi_subdevice *s)
536 {
537         struct comedi_cmd *cmd = &s->async->cmd;
538         unsigned int status;
539         unsigned int val;
540         int ret;
541 
542         status = inw(dev->iobase + PCI171x_STATUS);
543         if (status & Status_FE) {
544                 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
545                 s->async->events |= COMEDI_CB_ERROR;
546                 return;
547         }
548         if (status & Status_FF) {
549                 dev_dbg(dev->class_dev,
550                         "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
551                 s->async->events |= COMEDI_CB_ERROR;
552                 return;
553         }
554 
555         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
556 
557         for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
558                 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
559                 if (ret) {
560                         s->async->events |= COMEDI_CB_ERROR;
561                         break;
562                 }
563 
564                 comedi_buf_write_samples(s, &val, 1);
565 
566                 if (cmd->stop_src == TRIG_COUNT &&
567                     s->async->scans_done >= cmd->stop_arg) {
568                         s->async->events |= COMEDI_CB_EOA;
569                         break;
570                 }
571         }
572 
573         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
574 }
575 
576 static void pci1710_handle_fifo(struct comedi_device *dev,
577                                 struct comedi_subdevice *s)
578 {
579         struct pci1710_private *devpriv = dev->private;
580         struct comedi_async *async = s->async;
581         struct comedi_cmd *cmd = &async->cmd;
582         unsigned int status;
583         int i;
584 
585         status = inw(dev->iobase + PCI171x_STATUS);
586         if (!(status & Status_FH)) {
587                 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
588                 async->events |= COMEDI_CB_ERROR;
589                 return;
590         }
591         if (status & Status_FF) {
592                 dev_dbg(dev->class_dev,
593                         "A/D FIFO Full status (Fatal Error!)\n");
594                 async->events |= COMEDI_CB_ERROR;
595                 return;
596         }
597 
598         for (i = 0; i < devpriv->max_samples; i++) {
599                 unsigned int val;
600                 int ret;
601 
602                 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
603                 if (ret) {
604                         s->async->events |= COMEDI_CB_ERROR;
605                         break;
606                 }
607 
608                 if (!comedi_buf_write_samples(s, &val, 1))
609                         break;
610 
611                 if (cmd->stop_src == TRIG_COUNT &&
612                     async->scans_done >= cmd->stop_arg) {
613                         async->events |= COMEDI_CB_EOA;
614                         break;
615                 }
616         }
617 
618         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear our INT request */
619 }
620 
621 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
622 {
623         struct comedi_device *dev = d;
624         struct pci1710_private *devpriv = dev->private;
625         struct comedi_subdevice *s;
626         struct comedi_cmd *cmd;
627 
628         if (!dev->attached)     /*  is device attached? */
629                 return IRQ_NONE;        /*  no, exit */
630 
631         s = dev->read_subdev;
632         cmd = &s->async->cmd;
633 
634         /*  is this interrupt from our board? */
635         if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
636                 return IRQ_NONE;        /*  no, exit */
637 
638         if (devpriv->ai_et) {   /*  Switch from initial TRIG_EXT to TRIG_xxx. */
639                 devpriv->ai_et = 0;
640                 devpriv->CntrlReg &= Control_CNT0;
641                 devpriv->CntrlReg |= Control_SW; /* set software trigger */
642                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
643                 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
644                 outb(0, dev->iobase + PCI171x_CLRFIFO);
645                 outb(0, dev->iobase + PCI171x_CLRINT);
646                 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
647                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
648                 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
649                 return IRQ_HANDLED;
650         }
651 
652         if (cmd->flags & CMDF_WAKE_EOS)
653                 pci1710_handle_every_sample(dev, s);
654         else
655                 pci1710_handle_fifo(dev, s);
656 
657         comedi_handle_events(dev, s);
658 
659         return IRQ_HANDLED;
660 }
661 
662 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
663 {
664         struct pci1710_private *devpriv = dev->private;
665         struct comedi_cmd *cmd = &s->async->cmd;
666 
667         pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
668                                   devpriv->saved_seglen);
669 
670         outb(0, dev->iobase + PCI171x_CLRFIFO);
671         outb(0, dev->iobase + PCI171x_CLRINT);
672 
673         devpriv->CntrlReg &= Control_CNT0;
674         if ((cmd->flags & CMDF_WAKE_EOS) == 0)
675                 devpriv->CntrlReg |= Control_ONEFH;
676 
677         if (cmd->convert_src == TRIG_TIMER) {
678                 comedi_8254_update_divisors(dev->pacer);
679 
680                 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
681                 if (cmd->start_src == TRIG_EXT) {
682                         devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
683                         devpriv->CntrlReg &=
684                             ~(Control_PACER | Control_ONEFH | Control_GATE);
685                         devpriv->CntrlReg |= Control_EXT;
686                         devpriv->ai_et = 1;
687                 } else {        /* TRIG_NOW */
688                         devpriv->ai_et = 0;
689                 }
690                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
691 
692                 if (cmd->start_src == TRIG_NOW)
693                         comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
694         } else {        /* TRIG_EXT */
695                 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
696                 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
697         }
698 
699         return 0;
700 }
701 
702 static int pci171x_ai_cmdtest(struct comedi_device *dev,
703                               struct comedi_subdevice *s,
704                               struct comedi_cmd *cmd)
705 {
706         int err = 0;
707 
708         /* Step 1 : check if triggers are trivially valid */
709 
710         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
711         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
712         err |= comedi_check_trigger_src(&cmd->convert_src,
713                                         TRIG_TIMER | TRIG_EXT);
714         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
715         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
716 
717         if (err)
718                 return 1;
719 
720         /* step 2a: make sure trigger sources are unique */
721 
722         err |= comedi_check_trigger_is_unique(cmd->start_src);
723         err |= comedi_check_trigger_is_unique(cmd->convert_src);
724         err |= comedi_check_trigger_is_unique(cmd->stop_src);
725 
726         /* step 2b: and mutually compatible */
727 
728         if (err)
729                 return 2;
730 
731         /* Step 3: check if arguments are trivially valid */
732 
733         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
734         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
735 
736         if (cmd->convert_src == TRIG_TIMER)
737                 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000);
738         else    /* TRIG_FOLLOW */
739                 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
740 
741         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
742                                            cmd->chanlist_len);
743 
744         if (cmd->stop_src == TRIG_COUNT)
745                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
746         else    /* TRIG_NONE */
747                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
748 
749         if (err)
750                 return 3;
751 
752         /* step 4: fix up any arguments */
753 
754         if (cmd->convert_src == TRIG_TIMER) {
755                 unsigned int arg = cmd->convert_arg;
756 
757                 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
758                 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
759         }
760 
761         if (err)
762                 return 4;
763 
764         /* Step 5: check channel list */
765 
766         err |= pci171x_ai_check_chanlist(dev, s, cmd);
767 
768         if (err)
769                 return 5;
770 
771         return 0;
772 }
773 
774 static int pci171x_insn_counter_config(struct comedi_device *dev,
775                                        struct comedi_subdevice *s,
776                                        struct comedi_insn *insn,
777                                        unsigned int *data)
778 {
779         struct pci1710_private *devpriv = dev->private;
780 
781         switch (data[0]) {
782         case INSN_CONFIG_SET_CLOCK_SRC:
783                 switch (data[1]) {
784                 case 0: /* internal */
785                         devpriv->ai_et_CntrlReg &= ~Control_CNT0;
786                         break;
787                 case 1: /* external */
788                         devpriv->ai_et_CntrlReg |= Control_CNT0;
789                         break;
790                 default:
791                         return -EINVAL;
792                 }
793                 outw(devpriv->ai_et_CntrlReg, dev->iobase + PCI171x_CONTROL);
794                 break;
795         case INSN_CONFIG_GET_CLOCK_SRC:
796                 if (devpriv->ai_et_CntrlReg & Control_CNT0) {
797                         data[1] = 1;
798                         data[2] = 0;
799                 } else {
800                         data[1] = 0;
801                         data[2] = I8254_OSC_BASE_10MHZ;
802                 }
803                 break;
804         default:
805                 return -EINVAL;
806         }
807 
808         return insn->n;
809 }
810 
811 static int pci171x_reset(struct comedi_device *dev)
812 {
813         const struct boardtype *board = dev->board_ptr;
814         struct pci1710_private *devpriv = dev->private;
815 
816         /* Software trigger, CNT0=external */
817         devpriv->CntrlReg = Control_SW | Control_CNT0;
818         /* reset any operations */
819         outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
820         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
821         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
822         devpriv->da_ranges = 0;
823         if (board->has_ao) {
824                 /* set DACs to 0..5V */
825                 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
826                 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
827                 outw(0, dev->iobase + PCI171x_DA2);
828         }
829         outw(0, dev->iobase + PCI171x_DO);      /*  digital outputs to 0 */
830         outb(0, dev->iobase + PCI171x_CLRFIFO); /*  clear FIFO */
831         outb(0, dev->iobase + PCI171x_CLRINT);  /*  clear INT request */
832 
833         return 0;
834 }
835 
836 static int pci1720_reset(struct comedi_device *dev)
837 {
838         struct pci1710_private *devpriv = dev->private;
839         /* set synchronous output mode */
840         outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
841         devpriv->da_ranges = 0xAA;
842         /* set all ranges to +/-5V */
843         outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
844         outw(0x0800, dev->iobase + PCI1720_DA0);        /*  set outputs to 0V */
845         outw(0x0800, dev->iobase + PCI1720_DA1);
846         outw(0x0800, dev->iobase + PCI1720_DA2);
847         outw(0x0800, dev->iobase + PCI1720_DA3);
848         outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
849 
850         return 0;
851 }
852 
853 static int pci1710_reset(struct comedi_device *dev)
854 {
855         const struct boardtype *board = dev->board_ptr;
856 
857         if (board->is_pci1720)
858                 return pci1720_reset(dev);
859 
860         return pci171x_reset(dev);
861 }
862 
863 static int pci1710_auto_attach(struct comedi_device *dev,
864                                unsigned long context)
865 {
866         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
867         const struct boardtype *board = NULL;
868         struct pci1710_private *devpriv;
869         struct comedi_subdevice *s;
870         int ret, subdev, n_subdevices;
871 
872         if (context < ARRAY_SIZE(boardtypes))
873                 board = &boardtypes[context];
874         if (!board)
875                 return -ENODEV;
876         dev->board_ptr = board;
877         dev->board_name = board->name;
878 
879         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
880         if (!devpriv)
881                 return -ENOMEM;
882 
883         ret = comedi_pci_enable(dev);
884         if (ret)
885                 return ret;
886         dev->iobase = pci_resource_start(pcidev, 2);
887 
888         dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE,
889                                       I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
890         if (!dev->pacer)
891                 return -ENOMEM;
892 
893         n_subdevices = 0;
894         if (board->n_aichan)
895                 n_subdevices++;
896         if (board->has_ao)
897                 n_subdevices++;
898         if (board->has_di_do)
899                 n_subdevices += 2;
900         if (board->has_counter)
901                 n_subdevices++;
902 
903         ret = comedi_alloc_subdevices(dev, n_subdevices);
904         if (ret)
905                 return ret;
906 
907         pci1710_reset(dev);
908 
909         if (board->has_irq && pcidev->irq) {
910                 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
911                                   IRQF_SHARED, dev->board_name, dev);
912                 if (ret == 0)
913                         dev->irq = pcidev->irq;
914         }
915 
916         subdev = 0;
917 
918         if (board->n_aichan) {
919                 s = &dev->subdevices[subdev];
920                 s->type         = COMEDI_SUBD_AI;
921                 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
922                 if (board->has_diff_ai)
923                         s->subdev_flags |= SDF_DIFF;
924                 s->n_chan       = board->n_aichan;
925                 s->maxdata      = 0x0fff;
926                 s->range_table  = board->rangelist_ai;
927                 s->insn_read    = pci171x_ai_insn_read;
928                 if (dev->irq) {
929                         dev->read_subdev = s;
930                         s->subdev_flags |= SDF_CMD_READ;
931                         s->len_chanlist = s->n_chan;
932                         s->do_cmdtest   = pci171x_ai_cmdtest;
933                         s->do_cmd       = pci171x_ai_cmd;
934                         s->cancel       = pci171x_ai_cancel;
935                 }
936                 subdev++;
937         }
938 
939         if (board->has_ao) {
940                 s = &dev->subdevices[subdev];
941                 s->type         = COMEDI_SUBD_AO;
942                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
943                 s->maxdata      = 0x0fff;
944                 if (board->is_pci1720) {
945                         s->n_chan       = 4;
946                         s->range_table  = &pci1720_ao_range;
947                         s->insn_write   = pci1720_ao_insn_write;
948                 } else {
949                         s->n_chan       = 2;
950                         s->range_table  = &pci171x_ao_range;
951                         s->insn_write   = pci171x_ao_insn_write;
952                 }
953 
954                 ret = comedi_alloc_subdev_readback(s);
955                 if (ret)
956                         return ret;
957 
958                 /* initialize the readback values to match the board reset */
959                 if (board->is_pci1720) {
960                         int i;
961 
962                         for (i = 0; i < s->n_chan; i++)
963                                 s->readback[i] = 0x0800;
964                 }
965 
966                 subdev++;
967         }
968 
969         if (board->has_di_do) {
970                 s = &dev->subdevices[subdev];
971                 s->type         = COMEDI_SUBD_DI;
972                 s->subdev_flags = SDF_READABLE;
973                 s->n_chan       = 16;
974                 s->maxdata      = 1;
975                 s->range_table  = &range_digital;
976                 s->insn_bits    = pci171x_di_insn_bits;
977                 subdev++;
978 
979                 s = &dev->subdevices[subdev];
980                 s->type         = COMEDI_SUBD_DO;
981                 s->subdev_flags = SDF_WRITABLE;
982                 s->n_chan       = 16;
983                 s->maxdata      = 1;
984                 s->range_table  = &range_digital;
985                 s->insn_bits    = pci171x_do_insn_bits;
986                 subdev++;
987         }
988 
989         /* Counter subdevice (8254) */
990         if (board->has_counter) {
991                 s = &dev->subdevices[subdev];
992                 comedi_8254_subdevice_init(s, dev->pacer);
993 
994                 dev->pacer->insn_config = pci171x_insn_counter_config;
995 
996                 /* counters 1 and 2 are used internally for the pacer */
997                 comedi_8254_set_busy(dev->pacer, 1, true);
998                 comedi_8254_set_busy(dev->pacer, 2, true);
999 
1000                 subdev++;
1001         }
1002 
1003         /* max_samples is half the FIFO size (2 bytes/sample) */
1004         devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
1005 
1006         return 0;
1007 }
1008 
1009 static void pci1710_detach(struct comedi_device *dev)
1010 {
1011         if (dev->iobase)
1012                 pci1710_reset(dev);
1013         comedi_pci_detach(dev);
1014 }
1015 
1016 static struct comedi_driver adv_pci1710_driver = {
1017         .driver_name    = "adv_pci1710",
1018         .module         = THIS_MODULE,
1019         .auto_attach    = pci1710_auto_attach,
1020         .detach         = pci1710_detach,
1021 };
1022 
1023 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1024                                  const struct pci_device_id *id)
1025 {
1026         return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1027                                       id->driver_data);
1028 }
1029 
1030 static const struct pci_device_id adv_pci1710_pci_table[] = {
1031         {
1032                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1033                                PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1034                 .driver_data = BOARD_PCI1710,
1035         }, {
1036                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1037                                PCI_VENDOR_ID_ADVANTECH, 0x0000),
1038                 .driver_data = BOARD_PCI1710,
1039         }, {
1040                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1041                                PCI_VENDOR_ID_ADVANTECH, 0xb100),
1042                 .driver_data = BOARD_PCI1710,
1043         }, {
1044                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1045                                PCI_VENDOR_ID_ADVANTECH, 0xb200),
1046                 .driver_data = BOARD_PCI1710,
1047         }, {
1048                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1049                                PCI_VENDOR_ID_ADVANTECH, 0xc100),
1050                 .driver_data = BOARD_PCI1710,
1051         }, {
1052                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1053                                PCI_VENDOR_ID_ADVANTECH, 0xc200),
1054                 .driver_data = BOARD_PCI1710,
1055         }, {
1056                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1057                 .driver_data = BOARD_PCI1710,
1058         }, {
1059                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1060                                PCI_VENDOR_ID_ADVANTECH, 0x0002),
1061                 .driver_data = BOARD_PCI1710HG,
1062         }, {
1063                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1064                                PCI_VENDOR_ID_ADVANTECH, 0xb102),
1065                 .driver_data = BOARD_PCI1710HG,
1066         }, {
1067                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1068                                PCI_VENDOR_ID_ADVANTECH, 0xb202),
1069                 .driver_data = BOARD_PCI1710HG,
1070         }, {
1071                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1072                                PCI_VENDOR_ID_ADVANTECH, 0xc102),
1073                 .driver_data = BOARD_PCI1710HG,
1074         }, {
1075                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1076                                PCI_VENDOR_ID_ADVANTECH, 0xc202),
1077                 .driver_data = BOARD_PCI1710HG,
1078         }, {
1079                 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1080                 .driver_data = BOARD_PCI1710HG,
1081         },
1082         { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1083         { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1084         { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1085         { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1086         { 0 }
1087 };
1088 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1089 
1090 static struct pci_driver adv_pci1710_pci_driver = {
1091         .name           = "adv_pci1710",
1092         .id_table       = adv_pci1710_pci_table,
1093         .probe          = adv_pci1710_pci_probe,
1094         .remove         = comedi_pci_auto_unconfig,
1095 };
1096 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1097 
1098 MODULE_AUTHOR("Comedi http://www.comedi.org");
1099 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1100 MODULE_LICENSE("GPL");
1101 

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