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#include <linux/module.h>
31#include <linux/interrupt.h>
32
33#include "../comedi_pci.h"
34
35#include "comedi_8254.h"
36#include "amcc_s5933.h"
37
38
39
40
41#define PCI171X_AD_DATA_REG 0x00
42#define PCI171X_SOFTTRG_REG 0x00
43#define PCI171X_RANGE_REG 0x02
44#define PCI171X_RANGE_DIFF BIT(5)
45#define PCI171X_RANGE_UNI BIT(4)
46#define PCI171X_RANGE_GAIN(x) (((x) & 0x7) << 0)
47#define PCI171X_MUX_REG 0x04
48#define PCI171X_MUX_CHANH(x) (((x) & 0xf) << 8)
49#define PCI171X_MUX_CHANL(x) (((x) & 0xf) << 0)
50#define PCI171X_MUX_CHAN(x) (PCI171X_MUX_CHANH(x) | PCI171X_MUX_CHANL(x))
51#define PCI171X_STATUS_REG 0x06
52#define PCI171X_STATUS_IRQ BIT(11)
53#define PCI171X_STATUS_FF BIT(10)
54#define PCI171X_STATUS_FH BIT(9)
55#define PCI171X_STATUS_FE BIT(8)
56#define PCI171X_CTRL_REG 0x06
57#define PCI171X_CTRL_CNT0 BIT(6)
58#define PCI171X_CTRL_ONEFH BIT(5)
59#define PCI171X_CTRL_IRQEN BIT(4)
60#define PCI171X_CTRL_GATE BIT(3)
61#define PCI171X_CTRL_EXT BIT(2)
62#define PCI171X_CTRL_PACER BIT(1)
63#define PCI171X_CTRL_SW BIT(0)
64#define PCI171X_CLRINT_REG 0x08
65#define PCI171X_CLRFIFO_REG 0x09
66#define PCI171X_DA_REG(x) (0x0a + ((x) * 2))
67#define PCI171X_DAREF_REG 0x0e
68#define PCI171X_DAREF(c, r) (((r) & 0x3) << ((c) * 2))
69#define PCI171X_DAREF_MASK(c) PCI171X_DAREF((c), 0x3)
70#define PCI171X_DI_REG 0x10
71#define PCI171X_DO_REG 0x10
72#define PCI171X_TIMER_BASE 0x18
73
74static const struct comedi_lrange pci1710_ai_range = {
75 9, {
76 BIP_RANGE(5),
77 BIP_RANGE(2.5),
78 BIP_RANGE(1.25),
79 BIP_RANGE(0.625),
80 BIP_RANGE(10),
81 UNI_RANGE(10),
82 UNI_RANGE(5),
83 UNI_RANGE(2.5),
84 UNI_RANGE(1.25)
85 }
86};
87
88static const struct comedi_lrange pci1710hg_ai_range = {
89 12, {
90 BIP_RANGE(5),
91 BIP_RANGE(0.5),
92 BIP_RANGE(0.05),
93 BIP_RANGE(0.005),
94 BIP_RANGE(10),
95 BIP_RANGE(1),
96 BIP_RANGE(0.1),
97 BIP_RANGE(0.01),
98 UNI_RANGE(10),
99 UNI_RANGE(1),
100 UNI_RANGE(0.1),
101 UNI_RANGE(0.01)
102 }
103};
104
105static const struct comedi_lrange pci1711_ai_range = {
106 5, {
107 BIP_RANGE(10),
108 BIP_RANGE(5),
109 BIP_RANGE(2.5),
110 BIP_RANGE(1.25),
111 BIP_RANGE(0.625)
112 }
113};
114
115static const struct comedi_lrange pci171x_ao_range = {
116 3, {
117 UNI_RANGE(5),
118 UNI_RANGE(10),
119 RANGE_ext(0, 1)
120 }
121};
122
123enum pci1710_boardid {
124 BOARD_PCI1710,
125 BOARD_PCI1710HG,
126 BOARD_PCI1711,
127 BOARD_PCI1713,
128 BOARD_PCI1731,
129};
130
131struct boardtype {
132 const char *name;
133 const struct comedi_lrange *ai_range;
134 unsigned int is_pci1711:1;
135 unsigned int is_pci1713:1;
136 unsigned int has_ao:1;
137};
138
139static const struct boardtype boardtypes[] = {
140 [BOARD_PCI1710] = {
141 .name = "pci1710",
142 .ai_range = &pci1710_ai_range,
143 .has_ao = 1,
144 },
145 [BOARD_PCI1710HG] = {
146 .name = "pci1710hg",
147 .ai_range = &pci1710hg_ai_range,
148 .has_ao = 1,
149 },
150 [BOARD_PCI1711] = {
151 .name = "pci1711",
152 .ai_range = &pci1711_ai_range,
153 .is_pci1711 = 1,
154 .has_ao = 1,
155 },
156 [BOARD_PCI1713] = {
157 .name = "pci1713",
158 .ai_range = &pci1710_ai_range,
159 .is_pci1713 = 1,
160 },
161 [BOARD_PCI1731] = {
162 .name = "pci1731",
163 .ai_range = &pci1711_ai_range,
164 .is_pci1711 = 1,
165 },
166};
167
168struct pci1710_private {
169 unsigned int max_samples;
170 unsigned int ctrl;
171 unsigned int ctrl_ext;
172 unsigned int mux_scan;
173 unsigned char ai_et;
174 unsigned int act_chanlist[32];
175 unsigned char saved_seglen;
176 unsigned char da_ranges;
177 unsigned char unipolar_gain;
178};
179
180static int pci1710_ai_check_chanlist(struct comedi_device *dev,
181 struct comedi_subdevice *s,
182 struct comedi_cmd *cmd)
183{
184 struct pci1710_private *devpriv = dev->private;
185 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
186 unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
187 unsigned int next_chan = (chan0 + 1) % s->n_chan;
188 unsigned int chansegment[32];
189 unsigned int seglen;
190 int i;
191
192 if (cmd->chanlist_len == 1) {
193 devpriv->saved_seglen = cmd->chanlist_len;
194 return 0;
195 }
196
197
198 chansegment[0] = cmd->chanlist[0];
199
200 for (i = 1; i < cmd->chanlist_len; i++) {
201 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
202 unsigned int aref = CR_AREF(cmd->chanlist[i]);
203
204 if (cmd->chanlist[0] == cmd->chanlist[i])
205 break;
206
207 if (aref == AREF_DIFF && (chan & 1)) {
208 dev_err(dev->class_dev,
209 "Odd channel cannot be differential input!\n");
210 return -EINVAL;
211 }
212
213 if (last_aref == AREF_DIFF)
214 next_chan = (next_chan + 1) % s->n_chan;
215 if (chan != next_chan) {
216 dev_err(dev->class_dev,
217 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
218 i, chan, next_chan, chan0);
219 return -EINVAL;
220 }
221
222
223 chansegment[i] = cmd->chanlist[i];
224 last_aref = aref;
225 }
226 seglen = i;
227
228 for (i = 0; i < cmd->chanlist_len; i++) {
229 if (cmd->chanlist[i] != chansegment[i % seglen]) {
230 dev_err(dev->class_dev,
231 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
232 i, CR_CHAN(chansegment[i]),
233 CR_RANGE(chansegment[i]),
234 CR_AREF(chansegment[i]),
235 CR_CHAN(cmd->chanlist[i % seglen]),
236 CR_RANGE(cmd->chanlist[i % seglen]),
237 CR_AREF(chansegment[i % seglen]));
238 return -EINVAL;
239 }
240 }
241 devpriv->saved_seglen = seglen;
242
243 return 0;
244}
245
246static void pci1710_ai_setup_chanlist(struct comedi_device *dev,
247 struct comedi_subdevice *s,
248 unsigned int *chanlist,
249 unsigned int n_chan,
250 unsigned int seglen)
251{
252 struct pci1710_private *devpriv = dev->private;
253 unsigned int first_chan = CR_CHAN(chanlist[0]);
254 unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
255 unsigned int i;
256
257 for (i = 0; i < seglen; i++) {
258 unsigned int chan = CR_CHAN(chanlist[i]);
259 unsigned int range = CR_RANGE(chanlist[i]);
260 unsigned int aref = CR_AREF(chanlist[i]);
261 unsigned int rangeval = 0;
262
263 if (aref == AREF_DIFF)
264 rangeval |= PCI171X_RANGE_DIFF;
265 if (comedi_range_is_unipolar(s, range)) {
266 rangeval |= PCI171X_RANGE_UNI;
267 range -= devpriv->unipolar_gain;
268 }
269 rangeval |= PCI171X_RANGE_GAIN(range);
270
271
272 outw(PCI171X_MUX_CHAN(chan), dev->iobase + PCI171X_MUX_REG);
273 outw(rangeval, dev->iobase + PCI171X_RANGE_REG);
274
275 devpriv->act_chanlist[i] = chan;
276 }
277 for ( ; i < n_chan; i++)
278 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
279
280
281 devpriv->mux_scan = PCI171X_MUX_CHANL(first_chan) |
282 PCI171X_MUX_CHANH(last_chan);
283 outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG);
284}
285
286static int pci1710_ai_eoc(struct comedi_device *dev,
287 struct comedi_subdevice *s,
288 struct comedi_insn *insn,
289 unsigned long context)
290{
291 unsigned int status;
292
293 status = inw(dev->iobase + PCI171X_STATUS_REG);
294 if ((status & PCI171X_STATUS_FE) == 0)
295 return 0;
296 return -EBUSY;
297}
298
299static int pci1710_ai_read_sample(struct comedi_device *dev,
300 struct comedi_subdevice *s,
301 unsigned int cur_chan,
302 unsigned int *val)
303{
304 const struct boardtype *board = dev->board_ptr;
305 struct pci1710_private *devpriv = dev->private;
306 unsigned int sample;
307 unsigned int chan;
308
309 sample = inw(dev->iobase + PCI171X_AD_DATA_REG);
310 if (!board->is_pci1713) {
311
312
313
314
315
316 chan = sample >> 12;
317 if (chan != devpriv->act_chanlist[cur_chan]) {
318 dev_err(dev->class_dev,
319 "A/D data droput: received from channel %d, expected %d\n",
320 chan, devpriv->act_chanlist[cur_chan]);
321 return -ENODATA;
322 }
323 }
324 *val = sample & s->maxdata;
325 return 0;
326}
327
328static int pci1710_ai_insn_read(struct comedi_device *dev,
329 struct comedi_subdevice *s,
330 struct comedi_insn *insn,
331 unsigned int *data)
332{
333 struct pci1710_private *devpriv = dev->private;
334 int ret = 0;
335 int i;
336
337
338 devpriv->ctrl |= PCI171X_CTRL_SW;
339 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
340
341 outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
342 outb(0, dev->iobase + PCI171X_CLRINT_REG);
343
344 pci1710_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
345
346 for (i = 0; i < insn->n; i++) {
347 unsigned int val;
348
349
350 outw(0, dev->iobase + PCI171X_SOFTTRG_REG);
351
352 ret = comedi_timeout(dev, s, insn, pci1710_ai_eoc, 0);
353 if (ret)
354 break;
355
356 ret = pci1710_ai_read_sample(dev, s, 0, &val);
357 if (ret)
358 break;
359
360 data[i] = val;
361 }
362
363
364 devpriv->ctrl &= ~PCI171X_CTRL_SW;
365 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
366
367 outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
368 outb(0, dev->iobase + PCI171X_CLRINT_REG);
369
370 return ret ? ret : insn->n;
371}
372
373static int pci1710_ai_cancel(struct comedi_device *dev,
374 struct comedi_subdevice *s)
375{
376 struct pci1710_private *devpriv = dev->private;
377
378
379 devpriv->ctrl &= PCI171X_CTRL_CNT0;
380 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
381
382
383 comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
384
385
386 outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
387 outb(0, dev->iobase + PCI171X_CLRINT_REG);
388
389 return 0;
390}
391
392static void pci1710_handle_every_sample(struct comedi_device *dev,
393 struct comedi_subdevice *s)
394{
395 struct comedi_cmd *cmd = &s->async->cmd;
396 unsigned int status;
397 unsigned int val;
398 int ret;
399
400 status = inw(dev->iobase + PCI171X_STATUS_REG);
401 if (status & PCI171X_STATUS_FE) {
402 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
403 s->async->events |= COMEDI_CB_ERROR;
404 return;
405 }
406 if (status & PCI171X_STATUS_FF) {
407 dev_dbg(dev->class_dev,
408 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
409 s->async->events |= COMEDI_CB_ERROR;
410 return;
411 }
412
413 outb(0, dev->iobase + PCI171X_CLRINT_REG);
414
415 for (; !(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_FE);) {
416 ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val);
417 if (ret) {
418 s->async->events |= COMEDI_CB_ERROR;
419 break;
420 }
421
422 comedi_buf_write_samples(s, &val, 1);
423
424 if (cmd->stop_src == TRIG_COUNT &&
425 s->async->scans_done >= cmd->stop_arg) {
426 s->async->events |= COMEDI_CB_EOA;
427 break;
428 }
429 }
430
431 outb(0, dev->iobase + PCI171X_CLRINT_REG);
432}
433
434static void pci1710_handle_fifo(struct comedi_device *dev,
435 struct comedi_subdevice *s)
436{
437 struct pci1710_private *devpriv = dev->private;
438 struct comedi_async *async = s->async;
439 struct comedi_cmd *cmd = &async->cmd;
440 unsigned int status;
441 int i;
442
443 status = inw(dev->iobase + PCI171X_STATUS_REG);
444 if (!(status & PCI171X_STATUS_FH)) {
445 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
446 async->events |= COMEDI_CB_ERROR;
447 return;
448 }
449 if (status & PCI171X_STATUS_FF) {
450 dev_dbg(dev->class_dev,
451 "A/D FIFO Full status (Fatal Error!)\n");
452 async->events |= COMEDI_CB_ERROR;
453 return;
454 }
455
456 for (i = 0; i < devpriv->max_samples; i++) {
457 unsigned int val;
458 int ret;
459
460 ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val);
461 if (ret) {
462 s->async->events |= COMEDI_CB_ERROR;
463 break;
464 }
465
466 if (!comedi_buf_write_samples(s, &val, 1))
467 break;
468
469 if (cmd->stop_src == TRIG_COUNT &&
470 async->scans_done >= cmd->stop_arg) {
471 async->events |= COMEDI_CB_EOA;
472 break;
473 }
474 }
475
476 outb(0, dev->iobase + PCI171X_CLRINT_REG);
477}
478
479static irqreturn_t pci1710_irq_handler(int irq, void *d)
480{
481 struct comedi_device *dev = d;
482 struct pci1710_private *devpriv = dev->private;
483 struct comedi_subdevice *s;
484 struct comedi_cmd *cmd;
485
486 if (!dev->attached)
487 return IRQ_NONE;
488
489 s = dev->read_subdev;
490 cmd = &s->async->cmd;
491
492
493 if (!(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_IRQ))
494 return IRQ_NONE;
495
496 if (devpriv->ai_et) {
497 devpriv->ai_et = 0;
498 devpriv->ctrl &= PCI171X_CTRL_CNT0;
499 devpriv->ctrl |= PCI171X_CTRL_SW;
500 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
501 devpriv->ctrl = devpriv->ctrl_ext;
502 outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
503 outb(0, dev->iobase + PCI171X_CLRINT_REG);
504
505 outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG);
506 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
507 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
508 return IRQ_HANDLED;
509 }
510
511 if (cmd->flags & CMDF_WAKE_EOS)
512 pci1710_handle_every_sample(dev, s);
513 else
514 pci1710_handle_fifo(dev, s);
515
516 comedi_handle_events(dev, s);
517
518 return IRQ_HANDLED;
519}
520
521static int pci1710_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
522{
523 struct pci1710_private *devpriv = dev->private;
524 struct comedi_cmd *cmd = &s->async->cmd;
525
526 pci1710_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
527 devpriv->saved_seglen);
528
529 outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
530 outb(0, dev->iobase + PCI171X_CLRINT_REG);
531
532 devpriv->ctrl &= PCI171X_CTRL_CNT0;
533 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
534 devpriv->ctrl |= PCI171X_CTRL_ONEFH;
535
536 if (cmd->convert_src == TRIG_TIMER) {
537 comedi_8254_update_divisors(dev->pacer);
538
539 devpriv->ctrl |= PCI171X_CTRL_PACER | PCI171X_CTRL_IRQEN;
540 if (cmd->start_src == TRIG_EXT) {
541 devpriv->ctrl_ext = devpriv->ctrl;
542 devpriv->ctrl &= ~(PCI171X_CTRL_PACER |
543 PCI171X_CTRL_ONEFH |
544 PCI171X_CTRL_GATE);
545 devpriv->ctrl |= PCI171X_CTRL_EXT;
546 devpriv->ai_et = 1;
547 } else {
548 devpriv->ai_et = 0;
549 }
550 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
551
552 if (cmd->start_src == TRIG_NOW)
553 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
554 } else {
555 devpriv->ctrl |= PCI171X_CTRL_EXT | PCI171X_CTRL_IRQEN;
556 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
557 }
558
559 return 0;
560}
561
562static int pci1710_ai_cmdtest(struct comedi_device *dev,
563 struct comedi_subdevice *s,
564 struct comedi_cmd *cmd)
565{
566 int err = 0;
567
568
569
570 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
571 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
572 err |= comedi_check_trigger_src(&cmd->convert_src,
573 TRIG_TIMER | TRIG_EXT);
574 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
575 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
576
577 if (err)
578 return 1;
579
580
581
582 err |= comedi_check_trigger_is_unique(cmd->start_src);
583 err |= comedi_check_trigger_is_unique(cmd->convert_src);
584 err |= comedi_check_trigger_is_unique(cmd->stop_src);
585
586
587
588 if (err)
589 return 2;
590
591
592
593 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
594 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
595
596 if (cmd->convert_src == TRIG_TIMER)
597 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000);
598 else
599 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
600
601 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
602 cmd->chanlist_len);
603
604 if (cmd->stop_src == TRIG_COUNT)
605 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
606 else
607 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
608
609 if (err)
610 return 3;
611
612
613
614 if (cmd->convert_src == TRIG_TIMER) {
615 unsigned int arg = cmd->convert_arg;
616
617 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
618 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
619 }
620
621 if (err)
622 return 4;
623
624
625
626 err |= pci1710_ai_check_chanlist(dev, s, cmd);
627
628 if (err)
629 return 5;
630
631 return 0;
632}
633
634static int pci1710_ao_insn_write(struct comedi_device *dev,
635 struct comedi_subdevice *s,
636 struct comedi_insn *insn,
637 unsigned int *data)
638{
639 struct pci1710_private *devpriv = dev->private;
640 unsigned int chan = CR_CHAN(insn->chanspec);
641 unsigned int range = CR_RANGE(insn->chanspec);
642 unsigned int val = s->readback[chan];
643 int i;
644
645 devpriv->da_ranges &= ~PCI171X_DAREF_MASK(chan);
646 devpriv->da_ranges |= PCI171X_DAREF(chan, range);
647 outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG);
648
649 for (i = 0; i < insn->n; i++) {
650 val = data[i];
651 outw(val, dev->iobase + PCI171X_DA_REG(chan));
652 }
653
654 s->readback[chan] = val;
655
656 return insn->n;
657}
658
659static int pci1710_di_insn_bits(struct comedi_device *dev,
660 struct comedi_subdevice *s,
661 struct comedi_insn *insn,
662 unsigned int *data)
663{
664 data[1] = inw(dev->iobase + PCI171X_DI_REG);
665
666 return insn->n;
667}
668
669static int pci1710_do_insn_bits(struct comedi_device *dev,
670 struct comedi_subdevice *s,
671 struct comedi_insn *insn,
672 unsigned int *data)
673{
674 if (comedi_dio_update_state(s, data))
675 outw(s->state, dev->iobase + PCI171X_DO_REG);
676
677 data[1] = s->state;
678
679 return insn->n;
680}
681
682static int pci1710_counter_insn_config(struct comedi_device *dev,
683 struct comedi_subdevice *s,
684 struct comedi_insn *insn,
685 unsigned int *data)
686{
687 struct pci1710_private *devpriv = dev->private;
688
689 switch (data[0]) {
690 case INSN_CONFIG_SET_CLOCK_SRC:
691 switch (data[1]) {
692 case 0:
693 devpriv->ctrl_ext &= ~PCI171X_CTRL_CNT0;
694 break;
695 case 1:
696 devpriv->ctrl_ext |= PCI171X_CTRL_CNT0;
697 break;
698 default:
699 return -EINVAL;
700 }
701 outw(devpriv->ctrl_ext, dev->iobase + PCI171X_CTRL_REG);
702 break;
703 case INSN_CONFIG_GET_CLOCK_SRC:
704 if (devpriv->ctrl_ext & PCI171X_CTRL_CNT0) {
705 data[1] = 1;
706 data[2] = 0;
707 } else {
708 data[1] = 0;
709 data[2] = I8254_OSC_BASE_1MHZ;
710 }
711 break;
712 default:
713 return -EINVAL;
714 }
715
716 return insn->n;
717}
718
719static void pci1710_reset(struct comedi_device *dev)
720{
721 const struct boardtype *board = dev->board_ptr;
722
723
724
725
726
727 outw(0, dev->iobase + PCI171X_CTRL_REG);
728
729
730 outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
731 outb(0, dev->iobase + PCI171X_CLRINT_REG);
732
733 if (board->has_ao) {
734
735 outb(0, dev->iobase + PCI171X_DAREF_REG);
736 outw(0, dev->iobase + PCI171X_DA_REG(0));
737 outw(0, dev->iobase + PCI171X_DA_REG(1));
738 }
739
740
741 outw(0, dev->iobase + PCI171X_DO_REG);
742}
743
744static int pci1710_auto_attach(struct comedi_device *dev,
745 unsigned long context)
746{
747 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
748 const struct boardtype *board = NULL;
749 struct pci1710_private *devpriv;
750 struct comedi_subdevice *s;
751 int ret, subdev, n_subdevices;
752 int i;
753
754 if (context < ARRAY_SIZE(boardtypes))
755 board = &boardtypes[context];
756 if (!board)
757 return -ENODEV;
758 dev->board_ptr = board;
759 dev->board_name = board->name;
760
761 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
762 if (!devpriv)
763 return -ENOMEM;
764
765 ret = comedi_pci_enable(dev);
766 if (ret)
767 return ret;
768 dev->iobase = pci_resource_start(pcidev, 2);
769
770 dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE,
771 I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
772 if (!dev->pacer)
773 return -ENOMEM;
774
775 n_subdevices = 1;
776 if (board->has_ao)
777 n_subdevices++;
778 if (!board->is_pci1713) {
779
780
781
782
783 n_subdevices += 3;
784 }
785
786 ret = comedi_alloc_subdevices(dev, n_subdevices);
787 if (ret)
788 return ret;
789
790 pci1710_reset(dev);
791
792 if (pcidev->irq) {
793 ret = request_irq(pcidev->irq, pci1710_irq_handler,
794 IRQF_SHARED, dev->board_name, dev);
795 if (ret == 0)
796 dev->irq = pcidev->irq;
797 }
798
799 subdev = 0;
800
801
802 s = &dev->subdevices[subdev++];
803 s->type = COMEDI_SUBD_AI;
804 s->subdev_flags = SDF_READABLE | SDF_GROUND;
805 if (!board->is_pci1711)
806 s->subdev_flags |= SDF_DIFF;
807 s->n_chan = board->is_pci1713 ? 32 : 16;
808 s->maxdata = 0x0fff;
809 s->range_table = board->ai_range;
810 s->insn_read = pci1710_ai_insn_read;
811 if (dev->irq) {
812 dev->read_subdev = s;
813 s->subdev_flags |= SDF_CMD_READ;
814 s->len_chanlist = s->n_chan;
815 s->do_cmdtest = pci1710_ai_cmdtest;
816 s->do_cmd = pci1710_ai_cmd;
817 s->cancel = pci1710_ai_cancel;
818 }
819
820
821 for (i = 0; i < s->range_table->length; i++) {
822 if (comedi_range_is_unipolar(s, i)) {
823 devpriv->unipolar_gain = i;
824 break;
825 }
826 }
827
828 if (board->has_ao) {
829
830 s = &dev->subdevices[subdev++];
831 s->type = COMEDI_SUBD_AO;
832 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
833 s->n_chan = 2;
834 s->maxdata = 0x0fff;
835 s->range_table = &pci171x_ao_range;
836 s->insn_write = pci1710_ao_insn_write;
837
838 ret = comedi_alloc_subdev_readback(s);
839 if (ret)
840 return ret;
841 }
842
843 if (!board->is_pci1713) {
844
845 s = &dev->subdevices[subdev++];
846 s->type = COMEDI_SUBD_DI;
847 s->subdev_flags = SDF_READABLE;
848 s->n_chan = 16;
849 s->maxdata = 1;
850 s->range_table = &range_digital;
851 s->insn_bits = pci1710_di_insn_bits;
852
853
854 s = &dev->subdevices[subdev++];
855 s->type = COMEDI_SUBD_DO;
856 s->subdev_flags = SDF_WRITABLE;
857 s->n_chan = 16;
858 s->maxdata = 1;
859 s->range_table = &range_digital;
860 s->insn_bits = pci1710_do_insn_bits;
861
862
863 s = &dev->subdevices[subdev++];
864 comedi_8254_subdevice_init(s, dev->pacer);
865
866 dev->pacer->insn_config = pci1710_counter_insn_config;
867
868
869 comedi_8254_set_busy(dev->pacer, 1, true);
870 comedi_8254_set_busy(dev->pacer, 2, true);
871 }
872
873
874 devpriv->max_samples = (board->is_pci1711) ? 512 : 2048;
875
876 return 0;
877}
878
879static struct comedi_driver adv_pci1710_driver = {
880 .driver_name = "adv_pci1710",
881 .module = THIS_MODULE,
882 .auto_attach = pci1710_auto_attach,
883 .detach = comedi_pci_detach,
884};
885
886static int adv_pci1710_pci_probe(struct pci_dev *dev,
887 const struct pci_device_id *id)
888{
889 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
890 id->driver_data);
891}
892
893static const struct pci_device_id adv_pci1710_pci_table[] = {
894 {
895 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
896 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
897 .driver_data = BOARD_PCI1710,
898 }, {
899 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
900 PCI_VENDOR_ID_ADVANTECH, 0x0000),
901 .driver_data = BOARD_PCI1710,
902 }, {
903 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
904 PCI_VENDOR_ID_ADVANTECH, 0xb100),
905 .driver_data = BOARD_PCI1710,
906 }, {
907 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
908 PCI_VENDOR_ID_ADVANTECH, 0xb200),
909 .driver_data = BOARD_PCI1710,
910 }, {
911 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
912 PCI_VENDOR_ID_ADVANTECH, 0xc100),
913 .driver_data = BOARD_PCI1710,
914 }, {
915 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
916 PCI_VENDOR_ID_ADVANTECH, 0xc200),
917 .driver_data = BOARD_PCI1710,
918 }, {
919 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
920 .driver_data = BOARD_PCI1710,
921 }, {
922 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
923 PCI_VENDOR_ID_ADVANTECH, 0x0002),
924 .driver_data = BOARD_PCI1710HG,
925 }, {
926 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
927 PCI_VENDOR_ID_ADVANTECH, 0xb102),
928 .driver_data = BOARD_PCI1710HG,
929 }, {
930 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
931 PCI_VENDOR_ID_ADVANTECH, 0xb202),
932 .driver_data = BOARD_PCI1710HG,
933 }, {
934 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
935 PCI_VENDOR_ID_ADVANTECH, 0xc102),
936 .driver_data = BOARD_PCI1710HG,
937 }, {
938 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
939 PCI_VENDOR_ID_ADVANTECH, 0xc202),
940 .driver_data = BOARD_PCI1710HG,
941 }, {
942 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
943 .driver_data = BOARD_PCI1710HG,
944 },
945 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
946 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
947 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
948 { 0 }
949};
950MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
951
952static struct pci_driver adv_pci1710_pci_driver = {
953 .name = "adv_pci1710",
954 .id_table = adv_pci1710_pci_table,
955 .probe = adv_pci1710_pci_probe,
956 .remove = comedi_pci_auto_unconfig,
957};
958module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
959
960MODULE_AUTHOR("Comedi http://www.comedi.org");
961MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
962MODULE_LICENSE("GPL");
963