Version:  2.0.40 2.2.26 2.4.37 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 4.2 4.3 4.4

Linux/drivers/staging/comedi/drivers/adv_pci1710.c

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

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