3 * Comedi driver for Advantech PCI-1710 series boards
4 * Author: Michal Dobes <dobes@tesnet.cz>
6 * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7 * for testing and information.
12 * Description: Comedi driver for Advantech PCI-1710 series boards
13 * Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG, PCI-1711,
15 * Author: Michal Dobes <dobes@tesnet.cz>
16 * Updated: Fri, 29 Oct 2015 17:19:35 -0700
19 * Configuration options: not applicable, uses PCI auto config
21 * This driver supports AI, AO, DI and DO subdevices.
22 * AI subdevice supports cmd and insn interface,
23 * other subdevices support only insn interface.
25 * The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
26 * driver cannot distinguish between them, as would be normal for a
30 #include <linux/module.h>
31 #include <linux/interrupt.h>
33 #include "../comedi_pci.h"
35 #include "comedi_8254.h"
36 #include "amcc_s5933.h"
39 * PCI BAR2 Register map (dev->iobase)
41 #define PCI171X_AD_DATA_REG 0x00 /* R: A/D data */
42 #define PCI171X_SOFTTRG_REG 0x00 /* W: soft trigger for A/D */
43 #define PCI171X_RANGE_REG 0x02 /* W: A/D gain/range register */
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 /* W: A/D multiplexor control */
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 /* R: status register */
52 #define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */
53 #define PCI171X_STATUS_FF BIT(10) /* 1=FIFO is full, fatal error */
54 #define PCI171X_STATUS_FH BIT(9) /* 1=FIFO is half full */
55 #define PCI171X_STATUS_FE BIT(8) /* 1=FIFO is empty */
56 #define PCI171X_CTRL_REG 0x06 /* W: control register */
57 #define PCI171X_CTRL_CNT0 BIT(6) /* 1=ext. clk, 0=int. 100kHz clk */
58 #define PCI171X_CTRL_ONEFH BIT(5) /* 1=on FIFO half full, 0=on sample */
59 #define PCI171X_CTRL_IRQEN BIT(4) /* 1=enable IRQ */
60 #define PCI171X_CTRL_GATE BIT(3) /* 1=enable ext. trigger GATE (8254?) */
61 #define PCI171X_CTRL_EXT BIT(2) /* 1=enable ext. trigger source */
62 #define PCI171X_CTRL_PACER BIT(1) /* 1=enable int. 8254 trigger source */
63 #define PCI171X_CTRL_SW BIT(0) /* 1=enable software trigger source */
64 #define PCI171X_CLRINT_REG 0x08 /* W: clear interrupts request */
65 #define PCI171X_CLRFIFO_REG 0x09 /* W: clear FIFO */
66 #define PCI171X_DA_REG(x) (0x0a + ((x) * 2)) /* W: D/A register */
67 #define PCI171X_DAREF_REG 0x0e /* W: D/A reference control */
68 #define PCI171X_DI_REG 0x10 /* R: digital inputs */
69 #define PCI171X_DO_REG 0x10 /* W: digital outputs */
70 #define PCI171X_TIMER_BASE 0x18 /* R/W: 8254 timer */
72 static const struct comedi_lrange pci1710_ai_range
= {
74 BIP_RANGE(5), /* gain 1 (0x00) */
75 BIP_RANGE(2.5), /* gain 2 (0x01) */
76 BIP_RANGE(1.25), /* gain 4 (0x02) */
77 BIP_RANGE(0.625), /* gain 8 (0x03) */
78 BIP_RANGE(10), /* gain 0.5 (0x04) */
79 UNI_RANGE(10), /* gain 1 (0x00 | UNI) */
80 UNI_RANGE(5), /* gain 2 (0x01 | UNI) */
81 UNI_RANGE(2.5), /* gain 4 (0x02 | UNI) */
82 UNI_RANGE(1.25) /* gain 8 (0x03 | UNI) */
86 static const struct comedi_lrange pci1710hg_ai_range
= {
88 BIP_RANGE(5), /* gain 1 (0x00) */
89 BIP_RANGE(0.5), /* gain 10 (0x01) */
90 BIP_RANGE(0.05), /* gain 100 (0x02) */
91 BIP_RANGE(0.005), /* gain 1000 (0x03) */
92 BIP_RANGE(10), /* gain 0.5 (0x04) */
93 BIP_RANGE(1), /* gain 5 (0x05) */
94 BIP_RANGE(0.1), /* gain 50 (0x06) */
95 BIP_RANGE(0.01), /* gain 500 (0x07) */
96 UNI_RANGE(10), /* gain 1 (0x00 | UNI) */
97 UNI_RANGE(1), /* gain 10 (0x01 | UNI) */
98 UNI_RANGE(0.1), /* gain 100 (0x02 | UNI) */
99 UNI_RANGE(0.01) /* gain 1000 (0x03 | UNI) */
103 static const struct comedi_lrange pci1711_ai_range
= {
105 BIP_RANGE(10), /* gain 1 (0x00) */
106 BIP_RANGE(5), /* gain 2 (0x01) */
107 BIP_RANGE(2.5), /* gain 4 (0x02) */
108 BIP_RANGE(1.25), /* gain 8 (0x03) */
109 BIP_RANGE(0.625) /* gain 16 (0x04) */
113 static const struct comedi_lrange pci171x_ao_range
= {
120 enum pci1710_boardid
{
129 const char *name
; /* board name */
130 int n_aichan
; /* num of A/D chans */
131 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
132 unsigned int is_pci1713
:1;
133 unsigned int has_large_fifo
:1; /* 4K or 1K FIFO */
134 unsigned int has_diff_ai
:1;
135 unsigned int has_ao
:1;
136 unsigned int has_di_do
:1;
139 static const struct boardtype boardtypes
[] = {
143 .rangelist_ai
= &pci1710_ai_range
,
149 [BOARD_PCI1710HG
] = {
152 .rangelist_ai
= &pci1710hg_ai_range
,
161 .rangelist_ai
= &pci1711_ai_range
,
168 .rangelist_ai
= &pci1710_ai_range
,
176 .rangelist_ai
= &pci1711_ai_range
,
181 struct pci1710_private
{
182 unsigned int max_samples
;
183 unsigned int ctrl
; /* control register value */
184 unsigned int ctrl_ext
; /* used to switch from TRIG_EXT to TRIG_xxx */
185 unsigned int mux_scan
; /* used to set the channel interval to scan */
187 unsigned int act_chanlist
[32]; /* list of scanned channel */
188 unsigned char saved_seglen
; /* len of the non-repeating chanlist */
189 unsigned char da_ranges
; /* copy of D/A outpit range register */
190 unsigned char unipolar_gain
; /* adjust for unipolar gain codes */
193 static int pci171x_ai_check_chanlist(struct comedi_device
*dev
,
194 struct comedi_subdevice
*s
,
195 struct comedi_cmd
*cmd
)
197 struct pci1710_private
*devpriv
= dev
->private;
198 unsigned int chan0
= CR_CHAN(cmd
->chanlist
[0]);
199 unsigned int last_aref
= CR_AREF(cmd
->chanlist
[0]);
200 unsigned int next_chan
= (chan0
+ 1) % s
->n_chan
;
201 unsigned int chansegment
[32];
205 if (cmd
->chanlist_len
== 1) {
206 devpriv
->saved_seglen
= cmd
->chanlist_len
;
210 /* first channel is always ok */
211 chansegment
[0] = cmd
->chanlist
[0];
213 for (i
= 1; i
< cmd
->chanlist_len
; i
++) {
214 unsigned int chan
= CR_CHAN(cmd
->chanlist
[i
]);
215 unsigned int aref
= CR_AREF(cmd
->chanlist
[i
]);
217 if (cmd
->chanlist
[0] == cmd
->chanlist
[i
])
218 break; /* we detected a loop, stop */
220 if (aref
== AREF_DIFF
&& (chan
& 1)) {
221 dev_err(dev
->class_dev
,
222 "Odd channel cannot be differential input!\n");
226 if (last_aref
== AREF_DIFF
)
227 next_chan
= (next_chan
+ 1) % s
->n_chan
;
228 if (chan
!= next_chan
) {
229 dev_err(dev
->class_dev
,
230 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
231 i
, chan
, next_chan
, chan0
);
235 /* next correct channel in list */
236 chansegment
[i
] = cmd
->chanlist
[i
];
241 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
242 if (cmd
->chanlist
[i
] != chansegment
[i
% seglen
]) {
243 dev_err(dev
->class_dev
,
244 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
245 i
, CR_CHAN(chansegment
[i
]),
246 CR_RANGE(chansegment
[i
]),
247 CR_AREF(chansegment
[i
]),
248 CR_CHAN(cmd
->chanlist
[i
% seglen
]),
249 CR_RANGE(cmd
->chanlist
[i
% seglen
]),
250 CR_AREF(chansegment
[i
% seglen
]));
254 devpriv
->saved_seglen
= seglen
;
259 static void pci171x_ai_setup_chanlist(struct comedi_device
*dev
,
260 struct comedi_subdevice
*s
,
261 unsigned int *chanlist
,
265 struct pci1710_private
*devpriv
= dev
->private;
266 unsigned int first_chan
= CR_CHAN(chanlist
[0]);
267 unsigned int last_chan
= CR_CHAN(chanlist
[seglen
- 1]);
270 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
271 unsigned int chan
= CR_CHAN(chanlist
[i
]);
272 unsigned int range
= CR_RANGE(chanlist
[i
]);
273 unsigned int aref
= CR_AREF(chanlist
[i
]);
274 unsigned int rangeval
= 0;
276 if (aref
== AREF_DIFF
)
277 rangeval
|= PCI171X_RANGE_DIFF
;
278 if (comedi_range_is_unipolar(s
, range
)) {
279 rangeval
|= PCI171X_RANGE_UNI
;
280 range
-= devpriv
->unipolar_gain
;
282 rangeval
|= PCI171X_RANGE_GAIN(range
);
284 /* select channel and set range */
285 outw(PCI171X_MUX_CHAN(chan
), dev
->iobase
+ PCI171X_MUX_REG
);
286 outw(rangeval
, dev
->iobase
+ PCI171X_RANGE_REG
);
288 devpriv
->act_chanlist
[i
] = chan
;
290 for ( ; i
< n_chan
; i
++) /* store remainder of channel list */
291 devpriv
->act_chanlist
[i
] = CR_CHAN(chanlist
[i
]);
293 /* select channel interval to scan */
294 devpriv
->mux_scan
= PCI171X_MUX_CHANL(first_chan
) |
295 PCI171X_MUX_CHANH(last_chan
);
296 outw(devpriv
->mux_scan
, dev
->iobase
+ PCI171X_MUX_REG
);
299 static int pci171x_ai_eoc(struct comedi_device
*dev
,
300 struct comedi_subdevice
*s
,
301 struct comedi_insn
*insn
,
302 unsigned long context
)
306 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
307 if ((status
& PCI171X_STATUS_FE
) == 0)
312 static int pci171x_ai_read_sample(struct comedi_device
*dev
,
313 struct comedi_subdevice
*s
,
314 unsigned int cur_chan
,
317 const struct boardtype
*board
= dev
->board_ptr
;
318 struct pci1710_private
*devpriv
= dev
->private;
322 sample
= inw(dev
->iobase
+ PCI171X_AD_DATA_REG
);
323 if (!board
->is_pci1713
) {
325 * The upper 4 bits of the 16-bit sample are the channel number
326 * that the sample was acquired from. Verify that this channel
327 * number matches the expected channel number.
330 if (chan
!= devpriv
->act_chanlist
[cur_chan
]) {
331 dev_err(dev
->class_dev
,
332 "A/D data droput: received from channel %d, expected %d\n",
333 chan
, devpriv
->act_chanlist
[cur_chan
]);
337 *val
= sample
& s
->maxdata
;
341 static int pci171x_ai_insn_read(struct comedi_device
*dev
,
342 struct comedi_subdevice
*s
,
343 struct comedi_insn
*insn
,
346 struct pci1710_private
*devpriv
= dev
->private;
350 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
351 devpriv
->ctrl
|= PCI171X_CTRL_SW
; /* set software trigger */
352 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
353 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
354 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
356 pci171x_ai_setup_chanlist(dev
, s
, &insn
->chanspec
, 1, 1);
358 for (i
= 0; i
< insn
->n
; i
++) {
361 /* start conversion */
362 outw(0, dev
->iobase
+ PCI171X_SOFTTRG_REG
);
364 ret
= comedi_timeout(dev
, s
, insn
, pci171x_ai_eoc
, 0);
368 ret
= pci171x_ai_read_sample(dev
, s
, 0, &val
);
375 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
376 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
378 return ret
? ret
: insn
->n
;
381 static int pci171x_ao_insn_write(struct comedi_device
*dev
,
382 struct comedi_subdevice
*s
,
383 struct comedi_insn
*insn
,
386 struct pci1710_private
*devpriv
= dev
->private;
387 unsigned int chan
= CR_CHAN(insn
->chanspec
);
388 unsigned int range
= CR_RANGE(insn
->chanspec
);
389 unsigned int val
= s
->readback
[chan
];
392 devpriv
->da_ranges
&= ~(1 << (chan
<< 1));
393 devpriv
->da_ranges
|= (range
<< (chan
<< 1));
394 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171X_DAREF_REG
);
396 for (i
= 0; i
< insn
->n
; i
++) {
398 outw(val
, dev
->iobase
+ PCI171X_DA_REG(chan
));
401 s
->readback
[chan
] = val
;
406 static int pci171x_di_insn_bits(struct comedi_device
*dev
,
407 struct comedi_subdevice
*s
,
408 struct comedi_insn
*insn
,
411 data
[1] = inw(dev
->iobase
+ PCI171X_DI_REG
);
416 static int pci171x_do_insn_bits(struct comedi_device
*dev
,
417 struct comedi_subdevice
*s
,
418 struct comedi_insn
*insn
,
421 if (comedi_dio_update_state(s
, data
))
422 outw(s
->state
, dev
->iobase
+ PCI171X_DO_REG
);
429 static int pci171x_ai_cancel(struct comedi_device
*dev
,
430 struct comedi_subdevice
*s
)
432 struct pci1710_private
*devpriv
= dev
->private;
434 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
435 devpriv
->ctrl
|= PCI171X_CTRL_SW
;
436 /* reset any operations */
437 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
438 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, false);
439 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
440 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
445 static void pci1710_handle_every_sample(struct comedi_device
*dev
,
446 struct comedi_subdevice
*s
)
448 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
453 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
454 if (status
& PCI171X_STATUS_FE
) {
455 dev_dbg(dev
->class_dev
, "A/D FIFO empty (%4x)\n", status
);
456 s
->async
->events
|= COMEDI_CB_ERROR
;
459 if (status
& PCI171X_STATUS_FF
) {
460 dev_dbg(dev
->class_dev
,
461 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status
);
462 s
->async
->events
|= COMEDI_CB_ERROR
;
466 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
468 for (; !(inw(dev
->iobase
+ PCI171X_STATUS_REG
) & PCI171X_STATUS_FE
);) {
469 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
471 s
->async
->events
|= COMEDI_CB_ERROR
;
475 comedi_buf_write_samples(s
, &val
, 1);
477 if (cmd
->stop_src
== TRIG_COUNT
&&
478 s
->async
->scans_done
>= cmd
->stop_arg
) {
479 s
->async
->events
|= COMEDI_CB_EOA
;
484 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
487 static void pci1710_handle_fifo(struct comedi_device
*dev
,
488 struct comedi_subdevice
*s
)
490 struct pci1710_private
*devpriv
= dev
->private;
491 struct comedi_async
*async
= s
->async
;
492 struct comedi_cmd
*cmd
= &async
->cmd
;
496 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
497 if (!(status
& PCI171X_STATUS_FH
)) {
498 dev_dbg(dev
->class_dev
, "A/D FIFO not half full!\n");
499 async
->events
|= COMEDI_CB_ERROR
;
502 if (status
& PCI171X_STATUS_FF
) {
503 dev_dbg(dev
->class_dev
,
504 "A/D FIFO Full status (Fatal Error!)\n");
505 async
->events
|= COMEDI_CB_ERROR
;
509 for (i
= 0; i
< devpriv
->max_samples
; i
++) {
513 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
515 s
->async
->events
|= COMEDI_CB_ERROR
;
519 if (!comedi_buf_write_samples(s
, &val
, 1))
522 if (cmd
->stop_src
== TRIG_COUNT
&&
523 async
->scans_done
>= cmd
->stop_arg
) {
524 async
->events
|= COMEDI_CB_EOA
;
529 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
532 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
534 struct comedi_device
*dev
= d
;
535 struct pci1710_private
*devpriv
= dev
->private;
536 struct comedi_subdevice
*s
;
537 struct comedi_cmd
*cmd
;
539 if (!dev
->attached
) /* is device attached? */
540 return IRQ_NONE
; /* no, exit */
542 s
= dev
->read_subdev
;
543 cmd
= &s
->async
->cmd
;
545 /* is this interrupt from our board? */
546 if (!(inw(dev
->iobase
+ PCI171X_STATUS_REG
) & PCI171X_STATUS_IRQ
))
547 return IRQ_NONE
; /* no, exit */
549 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
551 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
552 devpriv
->ctrl
|= PCI171X_CTRL_SW
; /* set software trigger */
553 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
554 devpriv
->ctrl
= devpriv
->ctrl_ext
;
555 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
556 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
557 /* no sample on this interrupt; reset the channel interval */
558 outw(devpriv
->mux_scan
, dev
->iobase
+ PCI171X_MUX_REG
);
559 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
560 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, true);
564 if (cmd
->flags
& CMDF_WAKE_EOS
)
565 pci1710_handle_every_sample(dev
, s
);
567 pci1710_handle_fifo(dev
, s
);
569 comedi_handle_events(dev
, s
);
574 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
576 struct pci1710_private
*devpriv
= dev
->private;
577 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
579 pci171x_ai_setup_chanlist(dev
, s
, cmd
->chanlist
, cmd
->chanlist_len
,
580 devpriv
->saved_seglen
);
582 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
583 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
585 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
586 if ((cmd
->flags
& CMDF_WAKE_EOS
) == 0)
587 devpriv
->ctrl
|= PCI171X_CTRL_ONEFH
;
589 if (cmd
->convert_src
== TRIG_TIMER
) {
590 comedi_8254_update_divisors(dev
->pacer
);
592 devpriv
->ctrl
|= PCI171X_CTRL_PACER
| PCI171X_CTRL_IRQEN
;
593 if (cmd
->start_src
== TRIG_EXT
) {
594 devpriv
->ctrl_ext
= devpriv
->ctrl
;
595 devpriv
->ctrl
&= ~(PCI171X_CTRL_PACER
|
598 devpriv
->ctrl
|= PCI171X_CTRL_EXT
;
600 } else { /* TRIG_NOW */
603 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
605 if (cmd
->start_src
== TRIG_NOW
)
606 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, true);
607 } else { /* TRIG_EXT */
608 devpriv
->ctrl
|= PCI171X_CTRL_EXT
| PCI171X_CTRL_IRQEN
;
609 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
615 static int pci171x_ai_cmdtest(struct comedi_device
*dev
,
616 struct comedi_subdevice
*s
,
617 struct comedi_cmd
*cmd
)
621 /* Step 1 : check if triggers are trivially valid */
623 err
|= comedi_check_trigger_src(&cmd
->start_src
, TRIG_NOW
| TRIG_EXT
);
624 err
|= comedi_check_trigger_src(&cmd
->scan_begin_src
, TRIG_FOLLOW
);
625 err
|= comedi_check_trigger_src(&cmd
->convert_src
,
626 TRIG_TIMER
| TRIG_EXT
);
627 err
|= comedi_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
628 err
|= comedi_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
633 /* step 2a: make sure trigger sources are unique */
635 err
|= comedi_check_trigger_is_unique(cmd
->start_src
);
636 err
|= comedi_check_trigger_is_unique(cmd
->convert_src
);
637 err
|= comedi_check_trigger_is_unique(cmd
->stop_src
);
639 /* step 2b: and mutually compatible */
644 /* Step 3: check if arguments are trivially valid */
646 err
|= comedi_check_trigger_arg_is(&cmd
->start_arg
, 0);
647 err
|= comedi_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
649 if (cmd
->convert_src
== TRIG_TIMER
)
650 err
|= comedi_check_trigger_arg_min(&cmd
->convert_arg
, 10000);
651 else /* TRIG_FOLLOW */
652 err
|= comedi_check_trigger_arg_is(&cmd
->convert_arg
, 0);
654 err
|= comedi_check_trigger_arg_is(&cmd
->scan_end_arg
,
657 if (cmd
->stop_src
== TRIG_COUNT
)
658 err
|= comedi_check_trigger_arg_min(&cmd
->stop_arg
, 1);
660 err
|= comedi_check_trigger_arg_is(&cmd
->stop_arg
, 0);
665 /* step 4: fix up any arguments */
667 if (cmd
->convert_src
== TRIG_TIMER
) {
668 unsigned int arg
= cmd
->convert_arg
;
670 comedi_8254_cascade_ns_to_timer(dev
->pacer
, &arg
, cmd
->flags
);
671 err
|= comedi_check_trigger_arg_is(&cmd
->convert_arg
, arg
);
677 /* Step 5: check channel list */
679 err
|= pci171x_ai_check_chanlist(dev
, s
, cmd
);
687 static int pci171x_insn_counter_config(struct comedi_device
*dev
,
688 struct comedi_subdevice
*s
,
689 struct comedi_insn
*insn
,
692 struct pci1710_private
*devpriv
= dev
->private;
695 case INSN_CONFIG_SET_CLOCK_SRC
:
697 case 0: /* internal */
698 devpriv
->ctrl_ext
&= ~PCI171X_CTRL_CNT0
;
700 case 1: /* external */
701 devpriv
->ctrl_ext
|= PCI171X_CTRL_CNT0
;
706 outw(devpriv
->ctrl_ext
, dev
->iobase
+ PCI171X_CTRL_REG
);
708 case INSN_CONFIG_GET_CLOCK_SRC
:
709 if (devpriv
->ctrl_ext
& PCI171X_CTRL_CNT0
) {
714 data
[2] = I8254_OSC_BASE_10MHZ
;
724 static int pci1710_reset(struct comedi_device
*dev
)
726 const struct boardtype
*board
= dev
->board_ptr
;
727 struct pci1710_private
*devpriv
= dev
->private;
729 /* Software trigger, CNT0=external */
730 devpriv
->ctrl
= PCI171X_CTRL_SW
| PCI171X_CTRL_CNT0
;
731 /* reset any operations */
732 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
733 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
734 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
735 devpriv
->da_ranges
= 0;
737 /* set DACs to 0..5V and outputs to 0V */
738 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171X_DAREF_REG
);
739 outw(0, dev
->iobase
+ PCI171X_DA_REG(0));
740 outw(0, dev
->iobase
+ PCI171X_DA_REG(1));
742 outw(0, dev
->iobase
+ PCI171X_DO_REG
); /* digital outputs to 0 */
743 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
744 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
749 static int pci1710_auto_attach(struct comedi_device
*dev
,
750 unsigned long context
)
752 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
753 const struct boardtype
*board
= NULL
;
754 struct pci1710_private
*devpriv
;
755 struct comedi_subdevice
*s
;
756 int ret
, subdev
, n_subdevices
;
759 if (context
< ARRAY_SIZE(boardtypes
))
760 board
= &boardtypes
[context
];
763 dev
->board_ptr
= board
;
764 dev
->board_name
= board
->name
;
766 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
770 ret
= comedi_pci_enable(dev
);
773 dev
->iobase
= pci_resource_start(pcidev
, 2);
775 dev
->pacer
= comedi_8254_init(dev
->iobase
+ PCI171X_TIMER_BASE
,
776 I8254_OSC_BASE_10MHZ
, I8254_IO16
, 0);
785 if (board
->has_di_do
)
787 if (!board
->is_pci1713
) /* all other boards have a user counter */
790 ret
= comedi_alloc_subdevices(dev
, n_subdevices
);
797 ret
= request_irq(pcidev
->irq
, interrupt_service_pci1710
,
798 IRQF_SHARED
, dev
->board_name
, dev
);
800 dev
->irq
= pcidev
->irq
;
805 if (board
->n_aichan
) {
806 s
= &dev
->subdevices
[subdev
];
807 s
->type
= COMEDI_SUBD_AI
;
808 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
809 if (board
->has_diff_ai
)
810 s
->subdev_flags
|= SDF_DIFF
;
811 s
->n_chan
= board
->n_aichan
;
813 s
->range_table
= board
->rangelist_ai
;
814 s
->insn_read
= pci171x_ai_insn_read
;
816 dev
->read_subdev
= s
;
817 s
->subdev_flags
|= SDF_CMD_READ
;
818 s
->len_chanlist
= s
->n_chan
;
819 s
->do_cmdtest
= pci171x_ai_cmdtest
;
820 s
->do_cmd
= pci171x_ai_cmd
;
821 s
->cancel
= pci171x_ai_cancel
;
824 /* find the value needed to adjust for unipolar gain codes */
825 for (i
= 0; i
< s
->range_table
->length
; i
++) {
826 if (comedi_range_is_unipolar(s
, i
)) {
827 devpriv
->unipolar_gain
= i
;
836 s
= &dev
->subdevices
[subdev
];
837 s
->type
= COMEDI_SUBD_AO
;
838 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
841 s
->range_table
= &pci171x_ao_range
;
842 s
->insn_write
= pci171x_ao_insn_write
;
844 ret
= comedi_alloc_subdev_readback(s
);
851 if (board
->has_di_do
) {
852 s
= &dev
->subdevices
[subdev
];
853 s
->type
= COMEDI_SUBD_DI
;
854 s
->subdev_flags
= SDF_READABLE
;
857 s
->range_table
= &range_digital
;
858 s
->insn_bits
= pci171x_di_insn_bits
;
861 s
= &dev
->subdevices
[subdev
];
862 s
->type
= COMEDI_SUBD_DO
;
863 s
->subdev_flags
= SDF_WRITABLE
;
866 s
->range_table
= &range_digital
;
867 s
->insn_bits
= pci171x_do_insn_bits
;
871 if (!board
->is_pci1713
) {
872 /* Counter subdevice (8254) */
873 s
= &dev
->subdevices
[subdev
];
874 comedi_8254_subdevice_init(s
, dev
->pacer
);
876 dev
->pacer
->insn_config
= pci171x_insn_counter_config
;
878 /* counters 1 and 2 are used internally for the pacer */
879 comedi_8254_set_busy(dev
->pacer
, 1, true);
880 comedi_8254_set_busy(dev
->pacer
, 2, true);
885 /* max_samples is half the FIFO size (2 bytes/sample) */
886 devpriv
->max_samples
= (board
->has_large_fifo
) ? 2048 : 512;
891 static struct comedi_driver adv_pci1710_driver
= {
892 .driver_name
= "adv_pci1710",
893 .module
= THIS_MODULE
,
894 .auto_attach
= pci1710_auto_attach
,
895 .detach
= comedi_pci_detach
,
898 static int adv_pci1710_pci_probe(struct pci_dev
*dev
,
899 const struct pci_device_id
*id
)
901 return comedi_pci_auto_config(dev
, &adv_pci1710_driver
,
905 static const struct pci_device_id adv_pci1710_pci_table
[] = {
907 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
908 PCI_VENDOR_ID_PLX
, PCI_DEVICE_ID_PLX_9050
),
909 .driver_data
= BOARD_PCI1710
,
911 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
912 PCI_VENDOR_ID_ADVANTECH
, 0x0000),
913 .driver_data
= BOARD_PCI1710
,
915 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
916 PCI_VENDOR_ID_ADVANTECH
, 0xb100),
917 .driver_data
= BOARD_PCI1710
,
919 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
920 PCI_VENDOR_ID_ADVANTECH
, 0xb200),
921 .driver_data
= BOARD_PCI1710
,
923 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
924 PCI_VENDOR_ID_ADVANTECH
, 0xc100),
925 .driver_data
= BOARD_PCI1710
,
927 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
928 PCI_VENDOR_ID_ADVANTECH
, 0xc200),
929 .driver_data
= BOARD_PCI1710
,
931 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd100),
932 .driver_data
= BOARD_PCI1710
,
934 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
935 PCI_VENDOR_ID_ADVANTECH
, 0x0002),
936 .driver_data
= BOARD_PCI1710HG
,
938 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
939 PCI_VENDOR_ID_ADVANTECH
, 0xb102),
940 .driver_data
= BOARD_PCI1710HG
,
942 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
943 PCI_VENDOR_ID_ADVANTECH
, 0xb202),
944 .driver_data
= BOARD_PCI1710HG
,
946 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
947 PCI_VENDOR_ID_ADVANTECH
, 0xc102),
948 .driver_data
= BOARD_PCI1710HG
,
950 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
951 PCI_VENDOR_ID_ADVANTECH
, 0xc202),
952 .driver_data
= BOARD_PCI1710HG
,
954 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd102),
955 .driver_data
= BOARD_PCI1710HG
,
957 { PCI_VDEVICE(ADVANTECH
, 0x1711), BOARD_PCI1711
},
958 { PCI_VDEVICE(ADVANTECH
, 0x1713), BOARD_PCI1713
},
959 { PCI_VDEVICE(ADVANTECH
, 0x1731), BOARD_PCI1731
},
962 MODULE_DEVICE_TABLE(pci
, adv_pci1710_pci_table
);
964 static struct pci_driver adv_pci1710_pci_driver
= {
965 .name
= "adv_pci1710",
966 .id_table
= adv_pci1710_pci_table
,
967 .probe
= adv_pci1710_pci_probe
,
968 .remove
= comedi_pci_auto_unconfig
,
970 module_comedi_pci_driver(adv_pci1710_driver
, adv_pci1710_pci_driver
);
972 MODULE_AUTHOR("Comedi http://www.comedi.org");
973 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
974 MODULE_LICENSE("GPL");