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,
14 * PCI-1713, PCI-1720, PCI-1731
15 * Author: Michal Dobes <dobes@tesnet.cz>
18 * Configuration options: not applicable, uses PCI auto config
20 * This driver supports AI, AO, DI and DO subdevices.
21 * AI subdevice supports cmd and insn interface,
22 * other subdevices support only insn interface.
24 * The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
25 * driver cannot distinguish between them, as would be normal for a
29 #include <linux/module.h>
30 #include <linux/interrupt.h>
32 #include "../comedi_pci.h"
34 #include "comedi_8254.h"
35 #include "amcc_s5933.h"
38 * PCI BAR2 Register map (dev->iobase)
40 #define PCI171X_AD_DATA_REG 0x00 /* R: A/D data */
41 #define PCI171X_SOFTTRG_REG 0x00 /* W: soft trigger for A/D */
42 #define PCI171X_RANGE_REG 0x02 /* W: A/D gain/range register */
43 #define PCI171X_MUX_REG 0x04 /* W: A/D multiplexor control */
44 #define PCI171X_STATUS_REG 0x06 /* R: status register */
45 #define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */
46 #define PCI171X_STATUS_FF BIT(10) /* 1=FIFO is full, fatal error */
47 #define PCI171X_STATUS_FH BIT(9) /* 1=FIFO is half full */
48 #define PCI171X_STATUS_FE BIT(8) /* 1=FIFO is empty */
49 #define PCI171X_CTRL_REG 0x06 /* W: control register */
50 #define PCI171X_CTRL_CNT0 BIT(6) /* 1=ext. clk, 0=int. 100kHz clk */
51 #define PCI171X_CTRL_ONEFH BIT(5) /* 1=on FIFO half full, 0=on sample */
52 #define PCI171X_CTRL_IRQEN BIT(4) /* 1=enable IRQ */
53 #define PCI171X_CTRL_GATE BIT(3) /* 1=enable ext. trigger GATE (8254?) */
54 #define PCI171X_CTRL_EXT BIT(2) /* 1=enable ext. trigger source */
55 #define PCI171X_CTRL_PACER BIT(1) /* 1=enable int. 8254 trigger source */
56 #define PCI171X_CTRL_SW BIT(0) /* 1=enable software trigger source */
57 #define PCI171X_CLRINT_REG 0x08 /* W: clear interrupts request */
58 #define PCI171X_CLRFIFO_REG 0x09 /* W: clear FIFO */
59 #define PCI171X_DA_REG(x) (0x0a + ((x) * 2)) /* W: D/A register */
60 #define PCI171X_DAREF_REG 0x0e /* W: D/A reference control */
61 #define PCI171X_DI_REG 0x10 /* R: digital inputs */
62 #define PCI171X_DO_REG 0x10 /* W: digital outputs */
63 #define PCI171X_TIMER_BASE 0x18 /* R/W: 8254 timer */
66 * PCI-1720 only has analog outputs and has a different
67 * register map (dev->iobase)
69 #define PCI1720_DA_REG(x) (0x00 + ((x) * 2)) /* W: D/A registers */
70 #define PCI1720_RANGE_REG 0x08 /* R/W: D/A range register */
71 #define PCI1720_SYNC_REG 0x09 /* W: D/A synchronized output */
72 #define PCI1720_SYNC_CTRL_REG 0x0f /* R/W: D/A synchronized control */
73 #define PCI1720_SYNC_CTRL_SC0 BIT(0) /* set synchronous output mode */
75 static const struct comedi_lrange range_pci1710_3
= {
89 static const char range_codes_pci1710_3
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
90 0x10, 0x11, 0x12, 0x13 };
92 static const struct comedi_lrange range_pci1710hg
= {
109 static const char range_codes_pci1710hg
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
110 0x05, 0x06, 0x07, 0x10, 0x11,
113 static const struct comedi_lrange range_pci17x1
= {
123 static const char range_codes_pci17x1
[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
125 static const struct comedi_lrange pci1720_ao_range
= {
134 static const struct comedi_lrange pci171x_ao_range
= {
141 enum pci1710_boardid
{
151 const char *name
; /* board name */
152 int n_aichan
; /* num of A/D chans */
153 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
154 const char *rangecode_ai
; /* range codes for programming */
155 unsigned int is_pci1713
:1;
156 unsigned int is_pci1720
:1;
157 unsigned int has_irq
:1;
158 unsigned int has_large_fifo
:1; /* 4K or 1K FIFO */
159 unsigned int has_diff_ai
:1;
160 unsigned int has_ao
:1;
161 unsigned int has_di_do
:1;
162 unsigned int has_counter
:1;
165 static const struct boardtype boardtypes
[] = {
169 .rangelist_ai
= &range_pci1710_3
,
170 .rangecode_ai
= range_codes_pci1710_3
,
178 [BOARD_PCI1710HG
] = {
181 .rangelist_ai
= &range_pci1710hg
,
182 .rangecode_ai
= range_codes_pci1710hg
,
193 .rangelist_ai
= &range_pci17x1
,
194 .rangecode_ai
= range_codes_pci17x1
,
203 .rangelist_ai
= &range_pci1710_3
,
204 .rangecode_ai
= range_codes_pci1710_3
,
218 .rangelist_ai
= &range_pci17x1
,
219 .rangecode_ai
= range_codes_pci17x1
,
225 struct pci1710_private
{
226 unsigned int max_samples
;
227 unsigned int ctrl
; /* control register value */
228 unsigned int ctrl_ext
; /* used to switch from TRIG_EXT to TRIG_xxx */
229 unsigned int mux_ext
; /* used to set the channel interval to scan */
231 unsigned int act_chanlist
[32]; /* list of scanned channel */
232 unsigned char saved_seglen
; /* len of the non-repeating chanlist */
233 unsigned char da_ranges
; /* copy of D/A outpit range register */
236 static int pci171x_ai_check_chanlist(struct comedi_device
*dev
,
237 struct comedi_subdevice
*s
,
238 struct comedi_cmd
*cmd
)
240 struct pci1710_private
*devpriv
= dev
->private;
241 unsigned int chan0
= CR_CHAN(cmd
->chanlist
[0]);
242 unsigned int last_aref
= CR_AREF(cmd
->chanlist
[0]);
243 unsigned int next_chan
= (chan0
+ 1) % s
->n_chan
;
244 unsigned int chansegment
[32];
248 if (cmd
->chanlist_len
== 1) {
249 devpriv
->saved_seglen
= cmd
->chanlist_len
;
253 /* first channel is always ok */
254 chansegment
[0] = cmd
->chanlist
[0];
256 for (i
= 1; i
< cmd
->chanlist_len
; i
++) {
257 unsigned int chan
= CR_CHAN(cmd
->chanlist
[i
]);
258 unsigned int aref
= CR_AREF(cmd
->chanlist
[i
]);
260 if (cmd
->chanlist
[0] == cmd
->chanlist
[i
])
261 break; /* we detected a loop, stop */
263 if (aref
== AREF_DIFF
&& (chan
& 1)) {
264 dev_err(dev
->class_dev
,
265 "Odd channel cannot be differential input!\n");
269 if (last_aref
== AREF_DIFF
)
270 next_chan
= (next_chan
+ 1) % s
->n_chan
;
271 if (chan
!= next_chan
) {
272 dev_err(dev
->class_dev
,
273 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
274 i
, chan
, next_chan
, chan0
);
278 /* next correct channel in list */
279 chansegment
[i
] = cmd
->chanlist
[i
];
284 for (i
= 0; i
< cmd
->chanlist_len
; i
++) {
285 if (cmd
->chanlist
[i
] != chansegment
[i
% seglen
]) {
286 dev_err(dev
->class_dev
,
287 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
288 i
, CR_CHAN(chansegment
[i
]),
289 CR_RANGE(chansegment
[i
]),
290 CR_AREF(chansegment
[i
]),
291 CR_CHAN(cmd
->chanlist
[i
% seglen
]),
292 CR_RANGE(cmd
->chanlist
[i
% seglen
]),
293 CR_AREF(chansegment
[i
% seglen
]));
297 devpriv
->saved_seglen
= seglen
;
302 static void pci171x_ai_setup_chanlist(struct comedi_device
*dev
,
303 struct comedi_subdevice
*s
,
304 unsigned int *chanlist
,
308 const struct boardtype
*board
= dev
->board_ptr
;
309 struct pci1710_private
*devpriv
= dev
->private;
310 unsigned int first_chan
= CR_CHAN(chanlist
[0]);
311 unsigned int last_chan
= CR_CHAN(chanlist
[seglen
- 1]);
314 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
315 unsigned int chan
= CR_CHAN(chanlist
[i
]);
316 unsigned int range
= CR_RANGE(chanlist
[i
]);
317 unsigned int aref
= CR_AREF(chanlist
[i
]);
318 unsigned int rangeval
;
320 rangeval
= board
->rangecode_ai
[range
];
321 if (aref
== AREF_DIFF
)
324 /* select channel and set range */
325 outw(chan
| (chan
<< 8), dev
->iobase
+ PCI171X_MUX_REG
);
326 outw(rangeval
, dev
->iobase
+ PCI171X_RANGE_REG
);
328 devpriv
->act_chanlist
[i
] = chan
;
330 for ( ; i
< n_chan
; i
++) /* store remainder of channel list */
331 devpriv
->act_chanlist
[i
] = CR_CHAN(chanlist
[i
]);
333 /* select channel interval to scan */
334 devpriv
->mux_ext
= first_chan
| (last_chan
<< 8);
335 outw(devpriv
->mux_ext
, dev
->iobase
+ PCI171X_MUX_REG
);
338 static int pci171x_ai_eoc(struct comedi_device
*dev
,
339 struct comedi_subdevice
*s
,
340 struct comedi_insn
*insn
,
341 unsigned long context
)
345 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
346 if ((status
& PCI171X_STATUS_FE
) == 0)
351 static int pci171x_ai_read_sample(struct comedi_device
*dev
,
352 struct comedi_subdevice
*s
,
353 unsigned int cur_chan
,
356 const struct boardtype
*board
= dev
->board_ptr
;
357 struct pci1710_private
*devpriv
= dev
->private;
361 sample
= inw(dev
->iobase
+ PCI171X_AD_DATA_REG
);
362 if (!board
->is_pci1713
) {
364 * The upper 4 bits of the 16-bit sample are the channel number
365 * that the sample was acquired from. Verify that this channel
366 * number matches the expected channel number.
369 if (chan
!= devpriv
->act_chanlist
[cur_chan
]) {
370 dev_err(dev
->class_dev
,
371 "A/D data droput: received from channel %d, expected %d\n",
372 chan
, devpriv
->act_chanlist
[cur_chan
]);
376 *val
= sample
& s
->maxdata
;
380 static int pci171x_ai_insn_read(struct comedi_device
*dev
,
381 struct comedi_subdevice
*s
,
382 struct comedi_insn
*insn
,
385 struct pci1710_private
*devpriv
= dev
->private;
389 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
390 devpriv
->ctrl
|= PCI171X_CTRL_SW
; /* set software trigger */
391 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
392 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
393 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
395 pci171x_ai_setup_chanlist(dev
, s
, &insn
->chanspec
, 1, 1);
397 for (i
= 0; i
< insn
->n
; i
++) {
400 /* start conversion */
401 outw(0, dev
->iobase
+ PCI171X_SOFTTRG_REG
);
403 ret
= comedi_timeout(dev
, s
, insn
, pci171x_ai_eoc
, 0);
407 ret
= pci171x_ai_read_sample(dev
, s
, 0, &val
);
414 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
415 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
417 return ret
? ret
: insn
->n
;
420 static int pci171x_ao_insn_write(struct comedi_device
*dev
,
421 struct comedi_subdevice
*s
,
422 struct comedi_insn
*insn
,
425 struct pci1710_private
*devpriv
= dev
->private;
426 unsigned int chan
= CR_CHAN(insn
->chanspec
);
427 unsigned int range
= CR_RANGE(insn
->chanspec
);
428 unsigned int val
= s
->readback
[chan
];
431 devpriv
->da_ranges
&= ~(1 << (chan
<< 1));
432 devpriv
->da_ranges
|= (range
<< (chan
<< 1));
433 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171X_DAREF_REG
);
435 for (i
= 0; i
< insn
->n
; i
++) {
437 outw(val
, dev
->iobase
+ PCI171X_DA_REG(chan
));
440 s
->readback
[chan
] = val
;
445 static int pci171x_di_insn_bits(struct comedi_device
*dev
,
446 struct comedi_subdevice
*s
,
447 struct comedi_insn
*insn
,
450 data
[1] = inw(dev
->iobase
+ PCI171X_DI_REG
);
455 static int pci171x_do_insn_bits(struct comedi_device
*dev
,
456 struct comedi_subdevice
*s
,
457 struct comedi_insn
*insn
,
460 if (comedi_dio_update_state(s
, data
))
461 outw(s
->state
, dev
->iobase
+ PCI171X_DO_REG
);
468 static int pci1720_ao_insn_write(struct comedi_device
*dev
,
469 struct comedi_subdevice
*s
,
470 struct comedi_insn
*insn
,
473 struct pci1710_private
*devpriv
= dev
->private;
474 unsigned int chan
= CR_CHAN(insn
->chanspec
);
475 unsigned int range
= CR_RANGE(insn
->chanspec
);
479 val
= devpriv
->da_ranges
& (~(0x03 << (chan
<< 1)));
480 val
|= (range
<< (chan
<< 1));
481 if (val
!= devpriv
->da_ranges
) {
482 outb(val
, dev
->iobase
+ PCI1720_RANGE_REG
);
483 devpriv
->da_ranges
= val
;
486 val
= s
->readback
[chan
];
487 for (i
= 0; i
< insn
->n
; i
++) {
489 outw(val
, dev
->iobase
+ PCI1720_DA_REG(chan
));
490 outb(0, dev
->iobase
+ PCI1720_SYNC_REG
); /* update outputs */
493 s
->readback
[chan
] = val
;
498 static int pci171x_ai_cancel(struct comedi_device
*dev
,
499 struct comedi_subdevice
*s
)
501 struct pci1710_private
*devpriv
= dev
->private;
503 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
504 devpriv
->ctrl
|= PCI171X_CTRL_SW
;
505 /* reset any operations */
506 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
507 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, false);
508 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
509 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
514 static void pci1710_handle_every_sample(struct comedi_device
*dev
,
515 struct comedi_subdevice
*s
)
517 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
522 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
523 if (status
& PCI171X_STATUS_FE
) {
524 dev_dbg(dev
->class_dev
, "A/D FIFO empty (%4x)\n", status
);
525 s
->async
->events
|= COMEDI_CB_ERROR
;
528 if (status
& PCI171X_STATUS_FF
) {
529 dev_dbg(dev
->class_dev
,
530 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status
);
531 s
->async
->events
|= COMEDI_CB_ERROR
;
535 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
537 for (; !(inw(dev
->iobase
+ PCI171X_STATUS_REG
) & PCI171X_STATUS_FE
);) {
538 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
540 s
->async
->events
|= COMEDI_CB_ERROR
;
544 comedi_buf_write_samples(s
, &val
, 1);
546 if (cmd
->stop_src
== TRIG_COUNT
&&
547 s
->async
->scans_done
>= cmd
->stop_arg
) {
548 s
->async
->events
|= COMEDI_CB_EOA
;
553 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
556 static void pci1710_handle_fifo(struct comedi_device
*dev
,
557 struct comedi_subdevice
*s
)
559 struct pci1710_private
*devpriv
= dev
->private;
560 struct comedi_async
*async
= s
->async
;
561 struct comedi_cmd
*cmd
= &async
->cmd
;
565 status
= inw(dev
->iobase
+ PCI171X_STATUS_REG
);
566 if (!(status
& PCI171X_STATUS_FH
)) {
567 dev_dbg(dev
->class_dev
, "A/D FIFO not half full!\n");
568 async
->events
|= COMEDI_CB_ERROR
;
571 if (status
& PCI171X_STATUS_FF
) {
572 dev_dbg(dev
->class_dev
,
573 "A/D FIFO Full status (Fatal Error!)\n");
574 async
->events
|= COMEDI_CB_ERROR
;
578 for (i
= 0; i
< devpriv
->max_samples
; i
++) {
582 ret
= pci171x_ai_read_sample(dev
, s
, s
->async
->cur_chan
, &val
);
584 s
->async
->events
|= COMEDI_CB_ERROR
;
588 if (!comedi_buf_write_samples(s
, &val
, 1))
591 if (cmd
->stop_src
== TRIG_COUNT
&&
592 async
->scans_done
>= cmd
->stop_arg
) {
593 async
->events
|= COMEDI_CB_EOA
;
598 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
601 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
603 struct comedi_device
*dev
= d
;
604 struct pci1710_private
*devpriv
= dev
->private;
605 struct comedi_subdevice
*s
;
606 struct comedi_cmd
*cmd
;
608 if (!dev
->attached
) /* is device attached? */
609 return IRQ_NONE
; /* no, exit */
611 s
= dev
->read_subdev
;
612 cmd
= &s
->async
->cmd
;
614 /* is this interrupt from our board? */
615 if (!(inw(dev
->iobase
+ PCI171X_STATUS_REG
) & PCI171X_STATUS_IRQ
))
616 return IRQ_NONE
; /* no, exit */
618 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
620 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
621 devpriv
->ctrl
|= PCI171X_CTRL_SW
; /* set software trigger */
622 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
623 devpriv
->ctrl
= devpriv
->ctrl_ext
;
624 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
625 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
626 /* no sample on this interrupt; reset the channel interval */
627 outw(devpriv
->mux_ext
, dev
->iobase
+ PCI171X_MUX_REG
);
628 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
629 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, true);
633 if (cmd
->flags
& CMDF_WAKE_EOS
)
634 pci1710_handle_every_sample(dev
, s
);
636 pci1710_handle_fifo(dev
, s
);
638 comedi_handle_events(dev
, s
);
643 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
645 struct pci1710_private
*devpriv
= dev
->private;
646 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
648 pci171x_ai_setup_chanlist(dev
, s
, cmd
->chanlist
, cmd
->chanlist_len
,
649 devpriv
->saved_seglen
);
651 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
652 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
654 devpriv
->ctrl
&= PCI171X_CTRL_CNT0
;
655 if ((cmd
->flags
& CMDF_WAKE_EOS
) == 0)
656 devpriv
->ctrl
|= PCI171X_CTRL_ONEFH
;
658 if (cmd
->convert_src
== TRIG_TIMER
) {
659 comedi_8254_update_divisors(dev
->pacer
);
661 devpriv
->ctrl
|= PCI171X_CTRL_PACER
| PCI171X_CTRL_IRQEN
;
662 if (cmd
->start_src
== TRIG_EXT
) {
663 devpriv
->ctrl_ext
= devpriv
->ctrl
;
664 devpriv
->ctrl
&= ~(PCI171X_CTRL_PACER
|
667 devpriv
->ctrl
|= PCI171X_CTRL_EXT
;
669 } else { /* TRIG_NOW */
672 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
674 if (cmd
->start_src
== TRIG_NOW
)
675 comedi_8254_pacer_enable(dev
->pacer
, 1, 2, true);
676 } else { /* TRIG_EXT */
677 devpriv
->ctrl
|= PCI171X_CTRL_EXT
| PCI171X_CTRL_IRQEN
;
678 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
684 static int pci171x_ai_cmdtest(struct comedi_device
*dev
,
685 struct comedi_subdevice
*s
,
686 struct comedi_cmd
*cmd
)
690 /* Step 1 : check if triggers are trivially valid */
692 err
|= comedi_check_trigger_src(&cmd
->start_src
, TRIG_NOW
| TRIG_EXT
);
693 err
|= comedi_check_trigger_src(&cmd
->scan_begin_src
, TRIG_FOLLOW
);
694 err
|= comedi_check_trigger_src(&cmd
->convert_src
,
695 TRIG_TIMER
| TRIG_EXT
);
696 err
|= comedi_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
697 err
|= comedi_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
702 /* step 2a: make sure trigger sources are unique */
704 err
|= comedi_check_trigger_is_unique(cmd
->start_src
);
705 err
|= comedi_check_trigger_is_unique(cmd
->convert_src
);
706 err
|= comedi_check_trigger_is_unique(cmd
->stop_src
);
708 /* step 2b: and mutually compatible */
713 /* Step 3: check if arguments are trivially valid */
715 err
|= comedi_check_trigger_arg_is(&cmd
->start_arg
, 0);
716 err
|= comedi_check_trigger_arg_is(&cmd
->scan_begin_arg
, 0);
718 if (cmd
->convert_src
== TRIG_TIMER
)
719 err
|= comedi_check_trigger_arg_min(&cmd
->convert_arg
, 10000);
720 else /* TRIG_FOLLOW */
721 err
|= comedi_check_trigger_arg_is(&cmd
->convert_arg
, 0);
723 err
|= comedi_check_trigger_arg_is(&cmd
->scan_end_arg
,
726 if (cmd
->stop_src
== TRIG_COUNT
)
727 err
|= comedi_check_trigger_arg_min(&cmd
->stop_arg
, 1);
729 err
|= comedi_check_trigger_arg_is(&cmd
->stop_arg
, 0);
734 /* step 4: fix up any arguments */
736 if (cmd
->convert_src
== TRIG_TIMER
) {
737 unsigned int arg
= cmd
->convert_arg
;
739 comedi_8254_cascade_ns_to_timer(dev
->pacer
, &arg
, cmd
->flags
);
740 err
|= comedi_check_trigger_arg_is(&cmd
->convert_arg
, arg
);
746 /* Step 5: check channel list */
748 err
|= pci171x_ai_check_chanlist(dev
, s
, cmd
);
756 static int pci171x_insn_counter_config(struct comedi_device
*dev
,
757 struct comedi_subdevice
*s
,
758 struct comedi_insn
*insn
,
761 struct pci1710_private
*devpriv
= dev
->private;
764 case INSN_CONFIG_SET_CLOCK_SRC
:
766 case 0: /* internal */
767 devpriv
->ctrl_ext
&= ~PCI171X_CTRL_CNT0
;
769 case 1: /* external */
770 devpriv
->ctrl_ext
|= PCI171X_CTRL_CNT0
;
775 outw(devpriv
->ctrl_ext
, dev
->iobase
+ PCI171X_CTRL_REG
);
777 case INSN_CONFIG_GET_CLOCK_SRC
:
778 if (devpriv
->ctrl_ext
& PCI171X_CTRL_CNT0
) {
783 data
[2] = I8254_OSC_BASE_10MHZ
;
793 static int pci171x_reset(struct comedi_device
*dev
)
795 const struct boardtype
*board
= dev
->board_ptr
;
796 struct pci1710_private
*devpriv
= dev
->private;
798 /* Software trigger, CNT0=external */
799 devpriv
->ctrl
= PCI171X_CTRL_SW
| PCI171X_CTRL_CNT0
;
800 /* reset any operations */
801 outw(devpriv
->ctrl
, dev
->iobase
+ PCI171X_CTRL_REG
);
802 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
803 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
804 devpriv
->da_ranges
= 0;
806 /* set DACs to 0..5V and outputs to 0V */
807 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171X_DAREF_REG
);
808 outw(0, dev
->iobase
+ PCI171X_DA_REG(0));
809 outw(0, dev
->iobase
+ PCI171X_DA_REG(1));
811 outw(0, dev
->iobase
+ PCI171X_DO_REG
); /* digital outputs to 0 */
812 outb(0, dev
->iobase
+ PCI171X_CLRFIFO_REG
);
813 outb(0, dev
->iobase
+ PCI171X_CLRINT_REG
);
818 static int pci1720_reset(struct comedi_device
*dev
)
820 struct pci1710_private
*devpriv
= dev
->private;
821 /* set synchronous output mode */
822 outb(PCI1720_SYNC_CTRL_SC0
, dev
->iobase
+ PCI1720_SYNC_CTRL_REG
);
823 devpriv
->da_ranges
= 0xAA;
824 /* set all ranges to +/-5V and outputs to 0V */
825 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI1720_RANGE_REG
);
826 outw(0x0800, dev
->iobase
+ PCI1720_DA_REG(0));
827 outw(0x0800, dev
->iobase
+ PCI1720_DA_REG(1));
828 outw(0x0800, dev
->iobase
+ PCI1720_DA_REG(2));
829 outw(0x0800, dev
->iobase
+ PCI1720_DA_REG(3));
830 outb(0, dev
->iobase
+ PCI1720_SYNC_REG
); /* update outputs */
835 static int pci1710_reset(struct comedi_device
*dev
)
837 const struct boardtype
*board
= dev
->board_ptr
;
839 if (board
->is_pci1720
)
840 return pci1720_reset(dev
);
842 return pci171x_reset(dev
);
845 static int pci1710_auto_attach(struct comedi_device
*dev
,
846 unsigned long context
)
848 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
849 const struct boardtype
*board
= NULL
;
850 struct pci1710_private
*devpriv
;
851 struct comedi_subdevice
*s
;
852 int ret
, subdev
, n_subdevices
;
854 if (context
< ARRAY_SIZE(boardtypes
))
855 board
= &boardtypes
[context
];
858 dev
->board_ptr
= board
;
859 dev
->board_name
= board
->name
;
861 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
865 ret
= comedi_pci_enable(dev
);
868 dev
->iobase
= pci_resource_start(pcidev
, 2);
870 dev
->pacer
= comedi_8254_init(dev
->iobase
+ PCI171X_TIMER_BASE
,
871 I8254_OSC_BASE_10MHZ
, I8254_IO16
, 0);
880 if (board
->has_di_do
)
882 if (board
->has_counter
)
885 ret
= comedi_alloc_subdevices(dev
, n_subdevices
);
891 if (board
->has_irq
&& pcidev
->irq
) {
892 ret
= request_irq(pcidev
->irq
, interrupt_service_pci1710
,
893 IRQF_SHARED
, dev
->board_name
, dev
);
895 dev
->irq
= pcidev
->irq
;
900 if (board
->n_aichan
) {
901 s
= &dev
->subdevices
[subdev
];
902 s
->type
= COMEDI_SUBD_AI
;
903 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
904 if (board
->has_diff_ai
)
905 s
->subdev_flags
|= SDF_DIFF
;
906 s
->n_chan
= board
->n_aichan
;
908 s
->range_table
= board
->rangelist_ai
;
909 s
->insn_read
= pci171x_ai_insn_read
;
911 dev
->read_subdev
= s
;
912 s
->subdev_flags
|= SDF_CMD_READ
;
913 s
->len_chanlist
= s
->n_chan
;
914 s
->do_cmdtest
= pci171x_ai_cmdtest
;
915 s
->do_cmd
= pci171x_ai_cmd
;
916 s
->cancel
= pci171x_ai_cancel
;
922 s
= &dev
->subdevices
[subdev
];
923 s
->type
= COMEDI_SUBD_AO
;
924 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
926 if (board
->is_pci1720
) {
928 s
->range_table
= &pci1720_ao_range
;
929 s
->insn_write
= pci1720_ao_insn_write
;
932 s
->range_table
= &pci171x_ao_range
;
933 s
->insn_write
= pci171x_ao_insn_write
;
936 ret
= comedi_alloc_subdev_readback(s
);
940 /* initialize the readback values to match the board reset */
941 if (board
->is_pci1720
) {
944 for (i
= 0; i
< s
->n_chan
; i
++)
945 s
->readback
[i
] = 0x0800;
951 if (board
->has_di_do
) {
952 s
= &dev
->subdevices
[subdev
];
953 s
->type
= COMEDI_SUBD_DI
;
954 s
->subdev_flags
= SDF_READABLE
;
957 s
->range_table
= &range_digital
;
958 s
->insn_bits
= pci171x_di_insn_bits
;
961 s
= &dev
->subdevices
[subdev
];
962 s
->type
= COMEDI_SUBD_DO
;
963 s
->subdev_flags
= SDF_WRITABLE
;
966 s
->range_table
= &range_digital
;
967 s
->insn_bits
= pci171x_do_insn_bits
;
971 /* Counter subdevice (8254) */
972 if (board
->has_counter
) {
973 s
= &dev
->subdevices
[subdev
];
974 comedi_8254_subdevice_init(s
, dev
->pacer
);
976 dev
->pacer
->insn_config
= pci171x_insn_counter_config
;
978 /* counters 1 and 2 are used internally for the pacer */
979 comedi_8254_set_busy(dev
->pacer
, 1, true);
980 comedi_8254_set_busy(dev
->pacer
, 2, true);
985 /* max_samples is half the FIFO size (2 bytes/sample) */
986 devpriv
->max_samples
= (board
->has_large_fifo
) ? 2048 : 512;
991 static void pci1710_detach(struct comedi_device
*dev
)
995 comedi_pci_detach(dev
);
998 static struct comedi_driver adv_pci1710_driver
= {
999 .driver_name
= "adv_pci1710",
1000 .module
= THIS_MODULE
,
1001 .auto_attach
= pci1710_auto_attach
,
1002 .detach
= pci1710_detach
,
1005 static int adv_pci1710_pci_probe(struct pci_dev
*dev
,
1006 const struct pci_device_id
*id
)
1008 return comedi_pci_auto_config(dev
, &adv_pci1710_driver
,
1012 static const struct pci_device_id adv_pci1710_pci_table
[] = {
1014 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1015 PCI_VENDOR_ID_PLX
, PCI_DEVICE_ID_PLX_9050
),
1016 .driver_data
= BOARD_PCI1710
,
1018 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1019 PCI_VENDOR_ID_ADVANTECH
, 0x0000),
1020 .driver_data
= BOARD_PCI1710
,
1022 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1023 PCI_VENDOR_ID_ADVANTECH
, 0xb100),
1024 .driver_data
= BOARD_PCI1710
,
1026 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1027 PCI_VENDOR_ID_ADVANTECH
, 0xb200),
1028 .driver_data
= BOARD_PCI1710
,
1030 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1031 PCI_VENDOR_ID_ADVANTECH
, 0xc100),
1032 .driver_data
= BOARD_PCI1710
,
1034 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1035 PCI_VENDOR_ID_ADVANTECH
, 0xc200),
1036 .driver_data
= BOARD_PCI1710
,
1038 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd100),
1039 .driver_data
= BOARD_PCI1710
,
1041 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1042 PCI_VENDOR_ID_ADVANTECH
, 0x0002),
1043 .driver_data
= BOARD_PCI1710HG
,
1045 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1046 PCI_VENDOR_ID_ADVANTECH
, 0xb102),
1047 .driver_data
= BOARD_PCI1710HG
,
1049 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1050 PCI_VENDOR_ID_ADVANTECH
, 0xb202),
1051 .driver_data
= BOARD_PCI1710HG
,
1053 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1054 PCI_VENDOR_ID_ADVANTECH
, 0xc102),
1055 .driver_data
= BOARD_PCI1710HG
,
1057 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710,
1058 PCI_VENDOR_ID_ADVANTECH
, 0xc202),
1059 .driver_data
= BOARD_PCI1710HG
,
1061 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH
, 0x1710, 0x1000, 0xd102),
1062 .driver_data
= BOARD_PCI1710HG
,
1064 { PCI_VDEVICE(ADVANTECH
, 0x1711), BOARD_PCI1711
},
1065 { PCI_VDEVICE(ADVANTECH
, 0x1713), BOARD_PCI1713
},
1066 { PCI_VDEVICE(ADVANTECH
, 0x1720), BOARD_PCI1720
},
1067 { PCI_VDEVICE(ADVANTECH
, 0x1731), BOARD_PCI1731
},
1070 MODULE_DEVICE_TABLE(pci
, adv_pci1710_pci_table
);
1072 static struct pci_driver adv_pci1710_pci_driver
= {
1073 .name
= "adv_pci1710",
1074 .id_table
= adv_pci1710_pci_table
,
1075 .probe
= adv_pci1710_pci_probe
,
1076 .remove
= comedi_pci_auto_unconfig
,
1078 module_comedi_pci_driver(adv_pci1710_driver
, adv_pci1710_pci_driver
);
1080 MODULE_AUTHOR("Comedi http://www.comedi.org");
1081 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1082 MODULE_LICENSE("GPL");