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_MUX_REG 0x04 /* W: A/D multiplexor control */
45 #define PCI171X_STATUS_REG 0x06 /* R: status register */
46 #define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */
47 #define PCI171X_STATUS_FF BIT(10) /* 1=FIFO is full, fatal error */
48 #define PCI171X_STATUS_FH BIT(9) /* 1=FIFO is half full */
49 #define PCI171X_STATUS_FE BIT(8) /* 1=FIFO is empty */
50 #define PCI171X_CTRL_REG 0x06 /* W: control register */
51 #define PCI171X_CTRL_CNT0 BIT(6) /* 1=ext. clk, 0=int. 100kHz clk */
52 #define PCI171X_CTRL_ONEFH BIT(5) /* 1=on FIFO half full, 0=on sample */
53 #define PCI171X_CTRL_IRQEN BIT(4) /* 1=enable IRQ */
54 #define PCI171X_CTRL_GATE BIT(3) /* 1=enable ext. trigger GATE (8254?) */
55 #define PCI171X_CTRL_EXT BIT(2) /* 1=enable ext. trigger source */
56 #define PCI171X_CTRL_PACER BIT(1) /* 1=enable int. 8254 trigger source */
57 #define PCI171X_CTRL_SW BIT(0) /* 1=enable software trigger source */
58 #define PCI171X_CLRINT_REG 0x08 /* W: clear interrupts request */
59 #define PCI171X_CLRFIFO_REG 0x09 /* W: clear FIFO */
60 #define PCI171X_DA_REG(x) (0x0a + ((x) * 2)) /* W: D/A register */
61 #define PCI171X_DAREF_REG 0x0e /* W: D/A reference control */
62 #define PCI171X_DI_REG 0x10 /* R: digital inputs */
63 #define PCI171X_DO_REG 0x10 /* W: digital outputs */
64 #define PCI171X_TIMER_BASE 0x18 /* R/W: 8254 timer */
66 static const struct comedi_lrange range_pci1710_3
= {
80 static const char range_codes_pci1710_3
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
81 0x10, 0x11, 0x12, 0x13 };
83 static const struct comedi_lrange range_pci1710hg
= {
100 static const char range_codes_pci1710hg
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
101 0x05, 0x06, 0x07, 0x10, 0x11,
104 static const struct comedi_lrange range_pci17x1
= {
114 static const char range_codes_pci17x1
[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
116 static const struct comedi_lrange pci171x_ao_range
= {
123 enum pci1710_boardid
{
132 const char *name
; /* board name */
133 int n_aichan
; /* num of A/D chans */
134 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
135 const char *rangecode_ai
; /* range codes for programming */
136 unsigned int is_pci1713
:1;
137 unsigned int has_irq
:1;
138 unsigned int has_large_fifo
:1; /* 4K or 1K FIFO */
139 unsigned int has_diff_ai
:1;
140 unsigned int has_ao
:1;
141 unsigned int has_di_do
:1;
142 unsigned int has_counter
:1;
145 static const struct boardtype boardtypes
[] = {
149 .rangelist_ai
= &range_pci1710_3
,
150 .rangecode_ai
= range_codes_pci1710_3
,
158 [BOARD_PCI1710HG
] = {
161 .rangelist_ai
= &range_pci1710hg
,
162 .rangecode_ai
= range_codes_pci1710hg
,
173 .rangelist_ai
= &range_pci17x1
,
174 .rangecode_ai
= range_codes_pci17x1
,
183 .rangelist_ai
= &range_pci1710_3
,
184 .rangecode_ai
= range_codes_pci1710_3
,
193 .rangelist_ai
= &range_pci17x1
,
194 .rangecode_ai
= range_codes_pci17x1
,
200 struct pci1710_private
{
201 unsigned int max_samples
;
202 unsigned int ctrl
; /* control register value */
203 unsigned int ctrl_ext
; /* used to switch from TRIG_EXT to TRIG_xxx */
204 unsigned int mux_ext
; /* used to set the channel interval to scan */
206 unsigned int act_chanlist
[32]; /* list of scanned channel */
207 unsigned char saved_seglen
; /* len of the non-repeating chanlist */
208 unsigned char da_ranges
; /* copy of D/A outpit range register */
211 static int pci171x_ai_check_chanlist(struct comedi_device
*dev
,
212 struct comedi_subdevice
*s
,
213 struct comedi_cmd
*cmd
)
215 struct pci1710_private
*devpriv
= dev
->private;
216 unsigned int chan0
= CR_CHAN(cmd
->chanlist
[0]);
217 unsigned int last_aref
= CR_AREF(cmd
->chanlist
[0]);
218 unsigned int next_chan
= (chan0
+ 1) % s
->n_chan
;
219 unsigned int chansegment
[32];
223 if (cmd
->chanlist_len
== 1) {
224 devpriv
->saved_seglen
= cmd
->chanlist_len
;
228 /* first channel is always ok */
229 chansegment
[0] = cmd
->chanlist
[0];
231 for (i
= 1; i
< cmd
->chanlist_len
; i
++) {
232 unsigned int chan
= CR_CHAN(cmd
->chanlist
[i
]);
233 unsigned int aref
= CR_AREF(cmd
->chanlist
[i
]);
235 if (cmd
->chanlist
[0] == cmd
->chanlist
[i
])
236 break; /* we detected a loop, stop */
238 if (aref
== AREF_DIFF
&& (chan
& 1)) {
239 dev_err(dev
->class_dev
,
240 "Odd channel cannot be differential input!\n");
244 if (last_aref
== AREF_DIFF
)
245 next_chan
= (next_chan
+ 1) % s
->n_chan
;
246 if (chan
!= next_chan
) {
247 dev_err(dev
->class_dev
,
248 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
249 i
, chan
, next_chan
, chan0
);
253 /* next correct channel in list */
254 chansegment
[i
] = cmd
->chanlist
[i
];
259 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
260 if (cmd
->chanlist
[i
] != chansegment
[i
% seglen
]) {
261 dev_err(dev
->class_dev
,
262 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
263 i
, CR_CHAN(chansegment
[i
]),
264 CR_RANGE(chansegment
[i
]),
265 CR_AREF(chansegment
[i
]),
266 CR_CHAN(cmd
->chanlist
[i
% seglen
]),
267 CR_RANGE(cmd
->chanlist
[i
% seglen
]),
268 CR_AREF(chansegment
[i
% seglen
]));
272 devpriv
->saved_seglen
= seglen
;
277 static void pci171x_ai_setup_chanlist(struct comedi_device
*dev
,
278 struct comedi_subdevice
*s
,
279 unsigned int *chanlist
,
283 const struct boardtype
*board
= dev
->board_ptr
;
284 struct pci1710_private
*devpriv
= dev
->private;
285 unsigned int first_chan
= CR_CHAN(chanlist
[0]);
286 unsigned int last_chan
= CR_CHAN(chanlist
[seglen
- 1]);
289 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
290 unsigned int chan
= CR_CHAN(chanlist
[i
]);
291 unsigned int range
= CR_RANGE(chanlist
[i
]);
292 unsigned int aref
= CR_AREF(chanlist
[i
]);
293 unsigned int rangeval
;
295 rangeval
= board
->rangecode_ai
[range
];
296 if (aref
== AREF_DIFF
)
299 /* select channel and set range */
300 outw(chan
| (chan
<< 8), dev
->iobase
+ PCI171X_MUX_REG
);
301 outw(rangeval
, dev
->iobase
+ PCI171X_RANGE_REG
);
303 devpriv
->act_chanlist
[i
] = chan
;
305 for ( ; i
< n_chan
; i
++) /* store remainder of channel list */
306 devpriv
->act_chanlist
[i
] = CR_CHAN(chanlist
[i
]);
308 /* select channel interval to scan */
309 devpriv
->mux_ext
= first_chan
| (last_chan
<< 8);
310 outw(devpriv
->mux_ext
, dev
->iobase
+ PCI171X_MUX_REG
);
313 static int pci171x_ai_eoc(struct comedi_device
*dev
,
314 struct comedi_subdevice
*s
,
315 struct comedi_insn
*insn
,
316 unsigned long context
)
320 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
321 if ((status
& PCI171X_STATUS_FE
) == 0)
326 static int pci171x_ai_read_sample(struct comedi_device
*dev
,
327 struct comedi_subdevice
*s
,
328 unsigned int cur_chan
,
331 const struct boardtype
*board
= dev
->board_ptr
;
332 struct pci1710_private
*devpriv
= dev
->private;
336 sample
= inw(dev
->iobase
+ PCI171X_AD_DATA_REG
);
337 if (!board
->is_pci1713
) {
339 * The upper 4 bits of the 16-bit sample are the channel number
340 * that the sample was acquired from. Verify that this channel
341 * number matches the expected channel number.
344 if (chan
!= devpriv
->act_chanlist
[cur_chan
]) {
345 dev_err(dev
->class_dev
,
346 "A/D data droput: received from channel %d, expected %d\n",
347 chan
, devpriv
->act_chanlist
[cur_chan
]);
351 *val
= sample
& s
->maxdata
;
355 static int pci171x_ai_insn_read(struct comedi_device
*dev
,
356 struct comedi_subdevice
*s
,
357 struct comedi_insn
*insn
,
360 struct pci1710_private
*devpriv
= dev
->private;
364 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
365 devpriv
->ctrl
|= PCI171X_CTRL_SW
; /* set software trigger */
366 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
367 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
368 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
370 pci171x_ai_setup_chanlist(dev
, s
, &insn
->chanspec
, 1, 1);
372 for (i
= 0; i
< insn
->n
; i
++) {
375 /* start conversion */
376 outw(0, dev
->iobase
+ PCI171X_SOFTTRG_REG
);
378 ret
= comedi_timeout(dev
, s
, insn
, pci171x_ai_eoc
, 0);
382 ret
= pci171x_ai_read_sample(dev
, s
, 0, &val
);
389 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
390 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
392 return ret
? ret
: insn
->n
;
395 static int pci171x_ao_insn_write(struct comedi_device
*dev
,
396 struct comedi_subdevice
*s
,
397 struct comedi_insn
*insn
,
400 struct pci1710_private
*devpriv
= dev
->private;
401 unsigned int chan
= CR_CHAN(insn
->chanspec
);
402 unsigned int range
= CR_RANGE(insn
->chanspec
);
403 unsigned int val
= s
->readback
[chan
];
406 devpriv
->da_ranges
&= ~(1 << (chan
<< 1));
407 devpriv
->da_ranges
|= (range
<< (chan
<< 1));
408 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171X_DAREF_REG
);
410 for (i
= 0; i
< insn
->n
; i
++) {
412 outw(val
, dev
->iobase
+ PCI171X_DA_REG(chan
));
415 s
->readback
[chan
] = val
;
420 static int pci171x_di_insn_bits(struct comedi_device
*dev
,
421 struct comedi_subdevice
*s
,
422 struct comedi_insn
*insn
,
425 data
[1] = inw(dev
->iobase
+ PCI171X_DI_REG
);
430 static int pci171x_do_insn_bits(struct comedi_device
*dev
,
431 struct comedi_subdevice
*s
,
432 struct comedi_insn
*insn
,
435 if (comedi_dio_update_state(s
, data
))
436 outw(s
->state
, dev
->iobase
+ PCI171X_DO_REG
);
443 static int pci171x_ai_cancel(struct comedi_device
*dev
,
444 struct comedi_subdevice
*s
)
446 struct pci1710_private
*devpriv
= dev
->private;
448 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
449 devpriv
->ctrl
|= PCI171X_CTRL_SW
;
450 /* reset any operations */
451 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
452 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, false);
453 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
454 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
459 static void pci1710_handle_every_sample(struct comedi_device
*dev
,
460 struct comedi_subdevice
*s
)
462 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
467 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
468 if (status
& PCI171X_STATUS_FE
) {
469 dev_dbg(dev
->class_dev
, "A/D FIFO empty (%4x)\n", status
);
470 s
->async
->events
|= COMEDI_CB_ERROR
;
473 if (status
& PCI171X_STATUS_FF
) {
474 dev_dbg(dev
->class_dev
,
475 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status
);
476 s
->async
->events
|= COMEDI_CB_ERROR
;
480 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
482 for (; !(inw(dev
->iobase
+ PCI171X_STATUS_REG
) & PCI171X_STATUS_FE
);) {
483 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
485 s
->async
->events
|= COMEDI_CB_ERROR
;
489 comedi_buf_write_samples(s
, &val
, 1);
491 if (cmd
->stop_src
== TRIG_COUNT
&&
492 s
->async
->scans_done
>= cmd
->stop_arg
) {
493 s
->async
->events
|= COMEDI_CB_EOA
;
498 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
501 static void pci1710_handle_fifo(struct comedi_device
*dev
,
502 struct comedi_subdevice
*s
)
504 struct pci1710_private
*devpriv
= dev
->private;
505 struct comedi_async
*async
= s
->async
;
506 struct comedi_cmd
*cmd
= &async
->cmd
;
510 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
511 if (!(status
& PCI171X_STATUS_FH
)) {
512 dev_dbg(dev
->class_dev
, "A/D FIFO not half full!\n");
513 async
->events
|= COMEDI_CB_ERROR
;
516 if (status
& PCI171X_STATUS_FF
) {
517 dev_dbg(dev
->class_dev
,
518 "A/D FIFO Full status (Fatal Error!)\n");
519 async
->events
|= COMEDI_CB_ERROR
;
523 for (i
= 0; i
< devpriv
->max_samples
; i
++) {
527 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
529 s
->async
->events
|= COMEDI_CB_ERROR
;
533 if (!comedi_buf_write_samples(s
, &val
, 1))
536 if (cmd
->stop_src
== TRIG_COUNT
&&
537 async
->scans_done
>= cmd
->stop_arg
) {
538 async
->events
|= COMEDI_CB_EOA
;
543 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
546 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
548 struct comedi_device
*dev
= d
;
549 struct pci1710_private
*devpriv
= dev
->private;
550 struct comedi_subdevice
*s
;
551 struct comedi_cmd
*cmd
;
553 if (!dev
->attached
) /* is device attached? */
554 return IRQ_NONE
; /* no, exit */
556 s
= dev
->read_subdev
;
557 cmd
= &s
->async
->cmd
;
559 /* is this interrupt from our board? */
560 if (!(inw(dev
->iobase
+ PCI171X_STATUS_REG
) & PCI171X_STATUS_IRQ
))
561 return IRQ_NONE
; /* no, exit */
563 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
565 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
566 devpriv
->ctrl
|= PCI171X_CTRL_SW
; /* set software trigger */
567 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
568 devpriv
->ctrl
= devpriv
->ctrl_ext
;
569 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
570 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
571 /* no sample on this interrupt; reset the channel interval */
572 outw(devpriv
->mux_ext
, dev
->iobase
+ PCI171X_MUX_REG
);
573 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
574 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, true);
578 if (cmd
->flags
& CMDF_WAKE_EOS
)
579 pci1710_handle_every_sample(dev
, s
);
581 pci1710_handle_fifo(dev
, s
);
583 comedi_handle_events(dev
, s
);
588 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
590 struct pci1710_private
*devpriv
= dev
->private;
591 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
593 pci171x_ai_setup_chanlist(dev
, s
, cmd
->chanlist
, cmd
->chanlist_len
,
594 devpriv
->saved_seglen
);
596 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
597 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
599 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
600 if ((cmd
->flags
& CMDF_WAKE_EOS
) == 0)
601 devpriv
->ctrl
|= PCI171X_CTRL_ONEFH
;
603 if (cmd
->convert_src
== TRIG_TIMER
) {
604 comedi_8254_update_divisors(dev
->pacer
);
606 devpriv
->ctrl
|= PCI171X_CTRL_PACER
| PCI171X_CTRL_IRQEN
;
607 if (cmd
->start_src
== TRIG_EXT
) {
608 devpriv
->ctrl_ext
= devpriv
->ctrl
;
609 devpriv
->ctrl
&= ~(PCI171X_CTRL_PACER
|
612 devpriv
->ctrl
|= PCI171X_CTRL_EXT
;
614 } else { /* TRIG_NOW */
617 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
619 if (cmd
->start_src
== TRIG_NOW
)
620 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, true);
621 } else { /* TRIG_EXT */
622 devpriv
->ctrl
|= PCI171X_CTRL_EXT
| PCI171X_CTRL_IRQEN
;
623 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
629 static int pci171x_ai_cmdtest(struct comedi_device
*dev
,
630 struct comedi_subdevice
*s
,
631 struct comedi_cmd
*cmd
)
635 /* Step 1 : check if triggers are trivially valid */
637 err
|= comedi_check_trigger_src(&cmd
->start_src
, TRIG_NOW
| TRIG_EXT
);
638 err
|= comedi_check_trigger_src(&cmd
->scan_begin_src
, TRIG_FOLLOW
);
639 err
|= comedi_check_trigger_src(&cmd
->convert_src
,
640 TRIG_TIMER
| TRIG_EXT
);
641 err
|= comedi_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
642 err
|= comedi_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
647 /* step 2a: make sure trigger sources are unique */
649 err
|= comedi_check_trigger_is_unique(cmd
->start_src
);
650 err
|= comedi_check_trigger_is_unique(cmd
->convert_src
);
651 err
|= comedi_check_trigger_is_unique(cmd
->stop_src
);
653 /* step 2b: and mutually compatible */
658 /* Step 3: check if arguments are trivially valid */
660 err
|= comedi_check_trigger_arg_is(&cmd
->start_arg
, 0);
661 err
|= comedi_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
663 if (cmd
->convert_src
== TRIG_TIMER
)
664 err
|= comedi_check_trigger_arg_min(&cmd
->convert_arg
, 10000);
665 else /* TRIG_FOLLOW */
666 err
|= comedi_check_trigger_arg_is(&cmd
->convert_arg
, 0);
668 err
|= comedi_check_trigger_arg_is(&cmd
->scan_end_arg
,
671 if (cmd
->stop_src
== TRIG_COUNT
)
672 err
|= comedi_check_trigger_arg_min(&cmd
->stop_arg
, 1);
674 err
|= comedi_check_trigger_arg_is(&cmd
->stop_arg
, 0);
679 /* step 4: fix up any arguments */
681 if (cmd
->convert_src
== TRIG_TIMER
) {
682 unsigned int arg
= cmd
->convert_arg
;
684 comedi_8254_cascade_ns_to_timer(dev
->pacer
, &arg
, cmd
->flags
);
685 err
|= comedi_check_trigger_arg_is(&cmd
->convert_arg
, arg
);
691 /* Step 5: check channel list */
693 err
|= pci171x_ai_check_chanlist(dev
, s
, cmd
);
701 static int pci171x_insn_counter_config(struct comedi_device
*dev
,
702 struct comedi_subdevice
*s
,
703 struct comedi_insn
*insn
,
706 struct pci1710_private
*devpriv
= dev
->private;
709 case INSN_CONFIG_SET_CLOCK_SRC
:
711 case 0: /* internal */
712 devpriv
->ctrl_ext
&= ~PCI171X_CTRL_CNT0
;
714 case 1: /* external */
715 devpriv
->ctrl_ext
|= PCI171X_CTRL_CNT0
;
720 outw(devpriv
->ctrl_ext
, dev
->iobase
+ PCI171X_CTRL_REG
);
722 case INSN_CONFIG_GET_CLOCK_SRC
:
723 if (devpriv
->ctrl_ext
& PCI171X_CTRL_CNT0
) {
728 data
[2] = I8254_OSC_BASE_10MHZ
;
738 static int pci1710_reset(struct comedi_device
*dev
)
740 const struct boardtype
*board
= dev
->board_ptr
;
741 struct pci1710_private
*devpriv
= dev
->private;
743 /* Software trigger, CNT0=external */
744 devpriv
->ctrl
= PCI171X_CTRL_SW
| PCI171X_CTRL_CNT0
;
745 /* reset any operations */
746 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
747 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
748 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
749 devpriv
->da_ranges
= 0;
751 /* set DACs to 0..5V and outputs to 0V */
752 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171X_DAREF_REG
);
753 outw(0, dev
->iobase
+ PCI171X_DA_REG(0));
754 outw(0, dev
->iobase
+ PCI171X_DA_REG(1));
756 outw(0, dev
->iobase
+ PCI171X_DO_REG
); /* digital outputs to 0 */
757 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
758 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
763 static int pci1710_auto_attach(struct comedi_device
*dev
,
764 unsigned long context
)
766 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
767 const struct boardtype
*board
= NULL
;
768 struct pci1710_private
*devpriv
;
769 struct comedi_subdevice
*s
;
770 int ret
, subdev
, n_subdevices
;
772 if (context
< ARRAY_SIZE(boardtypes
))
773 board
= &boardtypes
[context
];
776 dev
->board_ptr
= board
;
777 dev
->board_name
= board
->name
;
779 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
783 ret
= comedi_pci_enable(dev
);
786 dev
->iobase
= pci_resource_start(pcidev
, 2);
788 dev
->pacer
= comedi_8254_init(dev
->iobase
+ PCI171X_TIMER_BASE
,
789 I8254_OSC_BASE_10MHZ
, I8254_IO16
, 0);
798 if (board
->has_di_do
)
800 if (board
->has_counter
)
803 ret
= comedi_alloc_subdevices(dev
, n_subdevices
);
809 if (board
->has_irq
&& pcidev
->irq
) {
810 ret
= request_irq(pcidev
->irq
, interrupt_service_pci1710
,
811 IRQF_SHARED
, dev
->board_name
, dev
);
813 dev
->irq
= pcidev
->irq
;
818 if (board
->n_aichan
) {
819 s
= &dev
->subdevices
[subdev
];
820 s
->type
= COMEDI_SUBD_AI
;
821 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
822 if (board
->has_diff_ai
)
823 s
->subdev_flags
|= SDF_DIFF
;
824 s
->n_chan
= board
->n_aichan
;
826 s
->range_table
= board
->rangelist_ai
;
827 s
->insn_read
= pci171x_ai_insn_read
;
829 dev
->read_subdev
= s
;
830 s
->subdev_flags
|= SDF_CMD_READ
;
831 s
->len_chanlist
= s
->n_chan
;
832 s
->do_cmdtest
= pci171x_ai_cmdtest
;
833 s
->do_cmd
= pci171x_ai_cmd
;
834 s
->cancel
= pci171x_ai_cancel
;
840 s
= &dev
->subdevices
[subdev
];
841 s
->type
= COMEDI_SUBD_AO
;
842 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
845 s
->range_table
= &pci171x_ao_range
;
846 s
->insn_write
= pci171x_ao_insn_write
;
848 ret
= comedi_alloc_subdev_readback(s
);
855 if (board
->has_di_do
) {
856 s
= &dev
->subdevices
[subdev
];
857 s
->type
= COMEDI_SUBD_DI
;
858 s
->subdev_flags
= SDF_READABLE
;
861 s
->range_table
= &range_digital
;
862 s
->insn_bits
= pci171x_di_insn_bits
;
865 s
= &dev
->subdevices
[subdev
];
866 s
->type
= COMEDI_SUBD_DO
;
867 s
->subdev_flags
= SDF_WRITABLE
;
870 s
->range_table
= &range_digital
;
871 s
->insn_bits
= pci171x_do_insn_bits
;
875 /* Counter subdevice (8254) */
876 if (board
->has_counter
) {
877 s
= &dev
->subdevices
[subdev
];
878 comedi_8254_subdevice_init(s
, dev
->pacer
);
880 dev
->pacer
->insn_config
= pci171x_insn_counter_config
;
882 /* counters 1 and 2 are used internally for the pacer */
883 comedi_8254_set_busy(dev
->pacer
, 1, true);
884 comedi_8254_set_busy(dev
->pacer
, 2, true);
889 /* max_samples is half the FIFO size (2 bytes/sample) */
890 devpriv
->max_samples
= (board
->has_large_fifo
) ? 2048 : 512;
895 static void pci1710_detach(struct comedi_device
*dev
)
899 comedi_pci_detach(dev
);
902 static struct comedi_driver adv_pci1710_driver
= {
903 .driver_name
= "adv_pci1710",
904 .module
= THIS_MODULE
,
905 .auto_attach
= pci1710_auto_attach
,
906 .detach
= pci1710_detach
,
909 static int adv_pci1710_pci_probe(struct pci_dev
*dev
,
910 const struct pci_device_id
*id
)
912 return comedi_pci_auto_config(dev
, &adv_pci1710_driver
,
916 static const struct pci_device_id adv_pci1710_pci_table
[] = {
918 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
919 PCI_VENDOR_ID_PLX
, PCI_DEVICE_ID_PLX_9050
),
920 .driver_data
= BOARD_PCI1710
,
922 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
923 PCI_VENDOR_ID_ADVANTECH
, 0x0000),
924 .driver_data
= BOARD_PCI1710
,
926 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
927 PCI_VENDOR_ID_ADVANTECH
, 0xb100),
928 .driver_data
= BOARD_PCI1710
,
930 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
931 PCI_VENDOR_ID_ADVANTECH
, 0xb200),
932 .driver_data
= BOARD_PCI1710
,
934 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
935 PCI_VENDOR_ID_ADVANTECH
, 0xc100),
936 .driver_data
= BOARD_PCI1710
,
938 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
939 PCI_VENDOR_ID_ADVANTECH
, 0xc200),
940 .driver_data
= BOARD_PCI1710
,
942 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd100),
943 .driver_data
= BOARD_PCI1710
,
945 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
946 PCI_VENDOR_ID_ADVANTECH
, 0x0002),
947 .driver_data
= BOARD_PCI1710HG
,
949 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
950 PCI_VENDOR_ID_ADVANTECH
, 0xb102),
951 .driver_data
= BOARD_PCI1710HG
,
953 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
954 PCI_VENDOR_ID_ADVANTECH
, 0xb202),
955 .driver_data
= BOARD_PCI1710HG
,
957 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
958 PCI_VENDOR_ID_ADVANTECH
, 0xc102),
959 .driver_data
= BOARD_PCI1710HG
,
961 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
962 PCI_VENDOR_ID_ADVANTECH
, 0xc202),
963 .driver_data
= BOARD_PCI1710HG
,
965 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd102),
966 .driver_data
= BOARD_PCI1710HG
,
968 { PCI_VDEVICE(ADVANTECH
, 0x1711), BOARD_PCI1711
},
969 { PCI_VDEVICE(ADVANTECH
, 0x1713), BOARD_PCI1713
},
970 { PCI_VDEVICE(ADVANTECH
, 0x1731), BOARD_PCI1731
},
973 MODULE_DEVICE_TABLE(pci
, adv_pci1710_pci_table
);
975 static struct pci_driver adv_pci1710_pci_driver
= {
976 .name
= "adv_pci1710",
977 .id_table
= adv_pci1710_pci_table
,
978 .probe
= adv_pci1710_pci_probe
,
979 .remove
= comedi_pci_auto_unconfig
,
981 module_comedi_pci_driver(adv_pci1710_driver
, adv_pci1710_pci_driver
);
983 MODULE_AUTHOR("Comedi http://www.comedi.org");
984 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
985 MODULE_LICENSE("GPL");