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