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