2 * comedi/drivers/adv_pci1710.c
4 * Author: Michal Dobes <dobes@tesnet.cz>
6 * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7 * for testing and informations.
9 * hardware driver for Advantech cards:
10 * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
11 * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731
14 * [0] - PCI bus number - if bus number and slot number are 0,
15 * then driver search for first unused card
16 * [1] - PCI slot number
21 Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
22 Advantech PCI-1720, PCI-1731
23 Author: Michal Dobes <dobes@tesnet.cz>
24 Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
25 PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
29 This driver supports AI, AO, DI and DO subdevices.
30 AI subdevice supports cmd and insn interface,
31 other subdevices support only insn interface.
33 The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
34 driver cannot distinguish between them, as would be normal for a
37 Configuration options:
38 [0] - PCI bus of device (optional)
39 [1] - PCI slot of device (optional)
40 If bus/slot is not specified, the first available PCI
44 #include <linux/interrupt.h>
46 #include "../comedidev.h"
48 #include "comedi_pci.h"
51 #include "amcc_s5933.h"
53 #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control correct channel number on every 12 bit sample */
55 #undef PCI171X_EXTDEBUG
57 #define DRV_NAME "adv_pci1710"
60 #ifdef PCI171X_EXTDEBUG
61 #define DPRINTK(fmt, args...) printk(fmt, ## args)
63 #define DPRINTK(fmt, args...)
66 /* hardware types of the cards */
67 #define TYPE_PCI171X 0
68 #define TYPE_PCI1713 2
69 #define TYPE_PCI1720 3
71 #define IORANGE_171x 32
72 #define IORANGE_1720 16
74 #define PCI171x_AD_DATA 0 /* R: A/D data */
75 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
76 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
77 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
78 #define PCI171x_STATUS 6 /* R: status register */
79 #define PCI171x_CONTROL 6 /* W: control register */
80 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
81 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
82 #define PCI171x_DA1 10 /* W: D/A register */
83 #define PCI171x_DA2 12 /* W: D/A register */
84 #define PCI171x_DAREF 14 /* W: D/A reference control */
85 #define PCI171x_DI 16 /* R: digi inputs */
86 #define PCI171x_DO 16 /* R: digi inputs */
87 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
88 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
89 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
90 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
92 /* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */
93 #define Status_FE 0x0100 /* 1=FIFO is empty */
94 #define Status_FH 0x0200 /* 1=FIFO is half full */
95 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
96 #define Status_IRQ 0x0800 /* 1=IRQ occured */
97 /* bits from control register (PCI171x_CONTROL) */
98 #define Control_CNT0 0x0040 /* 1=CNT0 have external source, 0=have internal 100kHz source */
99 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
100 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
101 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
102 #define Control_EXT 0x0004 /* 1=external trigger source */
103 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
104 #define Control_SW 0x0001 /* 1=enable software trigger source */
105 /* bits from counter control register (PCI171x_CNTCTRL) */
106 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
107 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
108 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
109 #define Counter_M2 0x0008
110 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
111 #define Counter_RW1 0x0020
112 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
113 #define Counter_SC1 0x0080 /* be used, 00 for CNT0, 11 for read-back command */
115 #define PCI1720_DA0 0 /* W: D/A register 0 */
116 #define PCI1720_DA1 2 /* W: D/A register 1 */
117 #define PCI1720_DA2 4 /* W: D/A register 2 */
118 #define PCI1720_DA3 6 /* W: D/A register 3 */
119 #define PCI1720_RANGE 8 /* R/W: D/A range register */
120 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
121 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
123 /* D/A synchronized control (PCI1720_SYNCONT) */
124 #define Syncont_SC0 1 /* set synchronous output mode */
126 static const struct comedi_lrange range_pci1710_3
= { 9, {
139 static const char range_codes_pci1710_3
[] =
140 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 };
142 static const struct comedi_lrange range_pci1710hg
= { 12, {
158 static const char range_codes_pci1710hg
[] =
159 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12,
163 static const struct comedi_lrange range_pci17x1
= { 5, {
172 static const char range_codes_pci17x1
[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
174 static const struct comedi_lrange range_pci1720
= { 4, {
182 static const struct comedi_lrange range_pci171x_da
= { 2, {
188 static int pci1710_attach(struct comedi_device
*dev
,
189 struct comedi_devconfig
*it
);
190 static int pci1710_detach(struct comedi_device
*dev
);
193 const char *name
; /* board name */
195 int iorange
; /* I/O range len */
196 char have_irq
; /* 1=card support IRQ */
197 char cardtype
; /* 0=1710& co. 2=1713, ... */
198 int n_aichan
; /* num of A/D chans */
199 int n_aichand
; /* num of A/D chans in diff mode */
200 int n_aochan
; /* num of D/A chans */
201 int n_dichan
; /* num of DI chans */
202 int n_dochan
; /* num of DO chans */
203 int n_counter
; /* num of counters */
204 int ai_maxdata
; /* resolution of A/D */
205 int ao_maxdata
; /* resolution of D/A */
206 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
207 const char *rangecode_ai
; /* range codes for programming */
208 const struct comedi_lrange
*rangelist_ao
; /* rangelist for D/A */
209 unsigned int ai_ns_min
; /* max sample speed of card v ns */
210 unsigned int fifo_half_size
; /* size of FIFO/2 */
213 static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table
) = {
215 PCI_VENDOR_ID_ADVANTECH
, 0x1710, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
216 PCI_VENDOR_ID_ADVANTECH
, 0x1711, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
217 PCI_VENDOR_ID_ADVANTECH
, 0x1713, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
218 PCI_VENDOR_ID_ADVANTECH
, 0x1720, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
219 PCI_VENDOR_ID_ADVANTECH
, 0x1731, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
223 MODULE_DEVICE_TABLE(pci
, pci1710_pci_table
);
225 static const struct boardtype boardtypes
[] = {
227 IORANGE_171x
, 1, TYPE_PCI171X
,
228 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
229 &range_pci1710_3
, range_codes_pci1710_3
,
232 {"pci1710hg", 0x1710,
233 IORANGE_171x
, 1, TYPE_PCI171X
,
234 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
235 &range_pci1710hg
, range_codes_pci1710hg
,
239 IORANGE_171x
, 1, TYPE_PCI171X
,
240 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
241 &range_pci17x1
, range_codes_pci17x1
, &range_pci171x_da
,
244 IORANGE_171x
, 1, TYPE_PCI1713
,
245 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
246 &range_pci1710_3
, range_codes_pci1710_3
, NULL
,
249 IORANGE_1720
, 0, TYPE_PCI1720
,
250 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
251 NULL
, NULL
, &range_pci1720
,
254 IORANGE_171x
, 1, TYPE_PCI171X
,
255 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
256 &range_pci17x1
, range_codes_pci17x1
, NULL
,
258 /* dummy entry corresponding to driver name */
262 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
264 static struct comedi_driver driver_pci1710
= {
265 .driver_name
= DRV_NAME
,
266 .module
= THIS_MODULE
,
267 .attach
= pci1710_attach
,
268 .detach
= pci1710_detach
,
269 .num_names
= n_boardtypes
,
270 .board_name
= &boardtypes
[0].name
,
271 .offset
= sizeof(struct boardtype
),
274 struct pci1710_private
{
275 struct pci_dev
*pcidev
; /* ptr to PCI device */
276 char valid
; /* card is usable */
277 char neverending_ai
; /* we do unlimited AI */
278 unsigned int CntrlReg
; /* Control register */
279 unsigned int i8254_osc_base
; /* frequence of onboard oscilator */
280 unsigned int ai_do
; /* what do AI? 0=nothing, 1 to 4 mode */
281 unsigned int ai_act_scan
; /* how many scans we finished */
282 unsigned int ai_act_chan
; /* actual position in actual scan */
283 unsigned int ai_buf_ptr
; /* data buffer ptr in samples */
284 unsigned char ai_eos
; /* 1=EOS wake up */
286 unsigned int ai_et_CntrlReg
;
287 unsigned int ai_et_MuxVal
;
288 unsigned int ai_et_div1
, ai_et_div2
;
289 unsigned int act_chanlist
[32]; /* list of scaned channel */
290 unsigned char act_chanlist_len
; /* len of scanlist */
291 unsigned char act_chanlist_pos
; /* actual position in MUX list */
292 unsigned char da_ranges
; /* copy of D/A outpit range register */
293 unsigned int ai_scans
; /* len of scanlist */
294 unsigned int ai_n_chan
; /* how many channels is measured */
295 unsigned int *ai_chanlist
; /* actaul chanlist */
296 unsigned int ai_flags
; /* flaglist */
297 unsigned int ai_data_len
; /* len of data buffer */
298 short *ai_data
; /* data buffer */
299 unsigned int ai_timer1
; /* timers */
300 unsigned int ai_timer2
;
301 short ao_data
[4]; /* data output buffer */
302 unsigned int cnt0_write_wait
; /* after a write, wait for update of the internal state */
305 #define devpriv ((struct pci1710_private *)dev->private)
306 #define this_board ((const struct boardtype *)dev->board_ptr)
309 ==============================================================================
312 static int check_channel_list(struct comedi_device
*dev
,
313 struct comedi_subdevice
*s
,
314 unsigned int *chanlist
, unsigned int n_chan
);
315 static void setup_channel_list(struct comedi_device
*dev
,
316 struct comedi_subdevice
*s
,
317 unsigned int *chanlist
, unsigned int n_chan
,
318 unsigned int seglen
);
319 static void start_pacer(struct comedi_device
*dev
, int mode
,
320 unsigned int divisor1
, unsigned int divisor2
);
321 static int pci1710_reset(struct comedi_device
*dev
);
322 static int pci171x_ai_cancel(struct comedi_device
*dev
,
323 struct comedi_subdevice
*s
);
325 static const unsigned int muxonechan
[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */
326 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
327 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
328 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
332 ==============================================================================
334 static int pci171x_insn_read_ai(struct comedi_device
*dev
,
335 struct comedi_subdevice
*s
,
336 struct comedi_insn
*insn
, unsigned int *data
)
339 #ifdef PCI171x_PARANOIDCHECK
343 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
344 devpriv
->CntrlReg
&= Control_CNT0
;
345 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
346 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
347 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
348 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
350 setup_channel_list(dev
, s
, &insn
->chanspec
, 1, 1);
352 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
353 inw(dev
->iobase
+ PCI171x_STATUS
),
354 dev
->iobase
+ PCI171x_STATUS
);
355 for (n
= 0; n
< insn
->n
; n
++) {
356 outw(0, dev
->iobase
+ PCI171x_SOFTTRG
); /* start conversion */
357 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n
,
358 inw(dev
->iobase
+ PCI171x_STATUS
));
360 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n
,
361 inw(dev
->iobase
+ PCI171x_STATUS
));
364 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
))
367 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n
,
369 inw(dev
->iobase
+ PCI171x_STATUS
));
371 comedi_error(dev
, "A/D insn timeout");
372 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
373 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
376 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
381 #ifdef PCI171x_PARANOIDCHECK
382 idata
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
383 if (this_board
->cardtype
!= TYPE_PCI1713
)
384 if ((idata
& 0xf000) != devpriv
->act_chanlist
[0]) {
385 comedi_error(dev
, "A/D insn data droput!");
388 data
[n
] = idata
& 0x0fff;
390 data
[n
] = inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff;
395 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
396 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
398 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n
);
403 ==============================================================================
405 static int pci171x_insn_write_ao(struct comedi_device
*dev
,
406 struct comedi_subdevice
*s
,
407 struct comedi_insn
*insn
, unsigned int *data
)
409 int n
, chan
, range
, ofs
;
411 chan
= CR_CHAN(insn
->chanspec
);
412 range
= CR_RANGE(insn
->chanspec
);
414 devpriv
->da_ranges
&= 0xfb;
415 devpriv
->da_ranges
|= (range
<< 2);
416 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
419 devpriv
->da_ranges
&= 0xfe;
420 devpriv
->da_ranges
|= range
;
421 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
425 for (n
= 0; n
< insn
->n
; n
++)
426 outw(data
[n
], dev
->iobase
+ ofs
);
428 devpriv
->ao_data
[chan
] = data
[n
];
435 ==============================================================================
437 static int pci171x_insn_read_ao(struct comedi_device
*dev
,
438 struct comedi_subdevice
*s
,
439 struct comedi_insn
*insn
, unsigned int *data
)
443 chan
= CR_CHAN(insn
->chanspec
);
444 for (n
= 0; n
< insn
->n
; n
++)
445 data
[n
] = devpriv
->ao_data
[chan
];
451 ==============================================================================
453 static int pci171x_insn_bits_di(struct comedi_device
*dev
,
454 struct comedi_subdevice
*s
,
455 struct comedi_insn
*insn
, unsigned int *data
)
457 data
[1] = inw(dev
->iobase
+ PCI171x_DI
);
463 ==============================================================================
465 static int pci171x_insn_bits_do(struct comedi_device
*dev
,
466 struct comedi_subdevice
*s
,
467 struct comedi_insn
*insn
, unsigned int *data
)
470 s
->state
&= ~data
[0];
471 s
->state
|= (data
[0] & data
[1]);
472 outw(s
->state
, dev
->iobase
+ PCI171x_DO
);
480 ==============================================================================
482 static int pci171x_insn_counter_read(struct comedi_device
*dev
,
483 struct comedi_subdevice
*s
,
484 struct comedi_insn
*insn
,
487 unsigned int msb
, lsb
, ccntrl
;
490 ccntrl
= 0xD2; /* count only */
491 for (i
= 0; i
< insn
->n
; i
++) {
492 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
494 lsb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
495 msb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
497 data
[0] = lsb
| (msb
<< 8);
504 ==============================================================================
506 static int pci171x_insn_counter_write(struct comedi_device
*dev
,
507 struct comedi_subdevice
*s
,
508 struct comedi_insn
*insn
,
511 uint msb
, lsb
, ccntrl
, status
;
513 lsb
= data
[0] & 0x00FF;
514 msb
= (data
[0] & 0xFF00) >> 8;
516 /* write lsb, then msb */
517 outw(lsb
, dev
->iobase
+ PCI171x_CNT0
);
518 outw(msb
, dev
->iobase
+ PCI171x_CNT0
);
520 if (devpriv
->cnt0_write_wait
) {
521 /* wait for the new count to be loaded */
524 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
525 status
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
526 } while (status
& 0x40);
533 ==============================================================================
535 static int pci171x_insn_counter_config(struct comedi_device
*dev
,
536 struct comedi_subdevice
*s
,
537 struct comedi_insn
*insn
,
541 /* This doesn't work like a normal Comedi counter config */
544 devpriv
->cnt0_write_wait
= data
[0] & 0x20;
546 /* internal or external clock? */
547 if (!(data
[0] & 0x10)) { /* internal */
548 devpriv
->CntrlReg
&= ~Control_CNT0
;
550 devpriv
->CntrlReg
|= Control_CNT0
;
552 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
555 ccntrl
|= Counter_M0
;
557 ccntrl
|= Counter_M1
;
559 ccntrl
|= Counter_M2
;
561 ccntrl
|= Counter_BCD
;
562 ccntrl
|= Counter_RW0
; /* set read/write mode */
563 ccntrl
|= Counter_RW1
;
564 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
571 ==============================================================================
573 static int pci1720_insn_write_ao(struct comedi_device
*dev
,
574 struct comedi_subdevice
*s
,
575 struct comedi_insn
*insn
, unsigned int *data
)
577 int n
, rangereg
, chan
;
579 chan
= CR_CHAN(insn
->chanspec
);
580 rangereg
= devpriv
->da_ranges
& (~(0x03 << (chan
<< 1)));
581 rangereg
|= (CR_RANGE(insn
->chanspec
) << (chan
<< 1));
582 if (rangereg
!= devpriv
->da_ranges
) {
583 outb(rangereg
, dev
->iobase
+ PCI1720_RANGE
);
584 devpriv
->da_ranges
= rangereg
;
587 for (n
= 0; n
< insn
->n
; n
++) {
588 outw(data
[n
], dev
->iobase
+ PCI1720_DA0
+ (chan
<< 1));
589 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
592 devpriv
->ao_data
[chan
] = data
[n
];
598 ==============================================================================
600 static void interrupt_pci1710_every_sample(void *d
)
602 struct comedi_device
*dev
= d
;
603 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
605 #ifdef PCI171x_PARANOIDCHECK
609 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
610 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
612 printk("comedi%d: A/D FIFO empty (%4x)\n", dev
->minor
, m
);
613 pci171x_ai_cancel(dev
, s
);
614 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
615 comedi_event(dev
, s
);
620 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
622 pci171x_ai_cancel(dev
, s
);
623 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
624 comedi_event(dev
, s
);
628 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
631 for (; !(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
);) {
632 #ifdef PCI171x_PARANOIDCHECK
633 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
634 DPRINTK("%04x:", sampl
);
635 if (this_board
->cardtype
!= TYPE_PCI1713
)
636 if ((sampl
& 0xf000) !=
637 devpriv
->act_chanlist
[s
->async
->cur_chan
]) {
639 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
640 (sampl
& 0xf000) >> 12,
643 async
->cur_chan
] & 0xf000) >>
645 pci171x_ai_cancel(dev
, s
);
647 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
648 comedi_event(dev
, s
);
651 DPRINTK("%8d %2d %8d~", s
->async
->buf_int_ptr
,
652 s
->async
->cur_chan
, s
->async
->buf_int_count
);
653 comedi_buf_put(s
->async
, sampl
& 0x0fff);
655 comedi_buf_put(s
->async
,
656 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
658 ++s
->async
->cur_chan
;
660 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
661 s
->async
->cur_chan
= 0;
664 if (s
->async
->cur_chan
== 0) { /* one scan done */
665 devpriv
->ai_act_scan
++;
667 ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
668 s
->async
->buf_int_count
, s
->async
->buf_int_ptr
,
669 s
->async
->buf_user_count
, s
->async
->buf_user_ptr
);
670 DPRINTK("adv_pci1710 EDBG: EOS2\n");
671 if ((!devpriv
->neverending_ai
) && (devpriv
->ai_act_scan
>= devpriv
->ai_scans
)) { /* all data sampled */
672 pci171x_ai_cancel(dev
, s
);
673 s
->async
->events
|= COMEDI_CB_EOA
;
674 comedi_event(dev
, s
);
680 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
681 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
683 comedi_event(dev
, s
);
687 ==============================================================================
689 static int move_block_from_fifo(struct comedi_device
*dev
,
690 struct comedi_subdevice
*s
, int n
, int turn
)
693 #ifdef PCI171x_PARANOIDCHECK
696 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n
,
698 j
= s
->async
->cur_chan
;
699 for (i
= 0; i
< n
; i
++) {
700 #ifdef PCI171x_PARANOIDCHECK
701 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
702 if (this_board
->cardtype
!= TYPE_PCI1713
)
703 if ((sampl
& 0xf000) != devpriv
->act_chanlist
[j
]) {
705 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
706 dev
->minor
, (sampl
& 0xf000) >> 12,
707 (devpriv
->act_chanlist
[j
] & 0xf000) >> 12,
708 i
, j
, devpriv
->ai_act_scan
, n
, turn
,
710 pci171x_ai_cancel(dev
, s
);
712 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
713 comedi_event(dev
, s
);
716 comedi_buf_put(s
->async
, sampl
& 0x0fff);
718 comedi_buf_put(s
->async
,
719 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
722 if (j
>= devpriv
->ai_n_chan
) {
724 devpriv
->ai_act_scan
++;
727 s
->async
->cur_chan
= j
;
728 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
733 ==============================================================================
735 static void interrupt_pci1710_half_fifo(void *d
)
737 struct comedi_device
*dev
= d
;
738 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
741 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
742 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
743 if (!(m
& Status_FH
)) {
744 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
746 pci171x_ai_cancel(dev
, s
);
747 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
748 comedi_event(dev
, s
);
753 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
755 pci171x_ai_cancel(dev
, s
);
756 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
757 comedi_event(dev
, s
);
761 samplesinbuf
= this_board
->fifo_half_size
;
762 if (samplesinbuf
* sizeof(short) >= devpriv
->ai_data_len
) {
763 m
= devpriv
->ai_data_len
/ sizeof(short);
764 if (move_block_from_fifo(dev
, s
, m
, 0))
770 if (move_block_from_fifo(dev
, s
, samplesinbuf
, 1))
774 if (!devpriv
->neverending_ai
)
775 if (devpriv
->ai_act_scan
>= devpriv
->ai_scans
) { /* all data sampled */
776 pci171x_ai_cancel(dev
, s
);
777 s
->async
->events
|= COMEDI_CB_EOA
;
778 comedi_event(dev
, s
);
781 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
782 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
784 comedi_event(dev
, s
);
788 ==============================================================================
790 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
792 struct comedi_device
*dev
= d
;
794 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
796 if (!dev
->attached
) /* is device attached? */
797 return IRQ_NONE
; /* no, exit */
799 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_IRQ
)) /* is this interrupt from our board? */
800 return IRQ_NONE
; /* no, exit */
802 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
803 inw(dev
->iobase
+ PCI171x_STATUS
));
805 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
807 devpriv
->CntrlReg
&= Control_CNT0
;
808 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
809 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
810 devpriv
->CntrlReg
= devpriv
->ai_et_CntrlReg
;
811 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
812 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
813 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
);
814 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
816 start_pacer(dev
, 1, devpriv
->ai_et_div1
, devpriv
->ai_et_div2
);
819 if (devpriv
->ai_eos
) { /* We use FIFO half full INT or not? */
820 interrupt_pci1710_every_sample(d
);
822 interrupt_pci1710_half_fifo(d
);
824 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
829 ==============================================================================
831 static int pci171x_ai_docmd_and_mode(int mode
, struct comedi_device
*dev
,
832 struct comedi_subdevice
*s
)
834 unsigned int divisor1
= 0, divisor2
= 0;
837 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
839 start_pacer(dev
, -1, 0, 0); /* stop pacer */
841 seglen
= check_channel_list(dev
, s
, devpriv
->ai_chanlist
,
845 setup_channel_list(dev
, s
, devpriv
->ai_chanlist
,
846 devpriv
->ai_n_chan
, seglen
);
848 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
849 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
851 devpriv
->ai_do
= mode
;
853 devpriv
->ai_act_scan
= 0;
854 s
->async
->cur_chan
= 0;
855 devpriv
->ai_buf_ptr
= 0;
856 devpriv
->neverending_ai
= 0;
858 devpriv
->CntrlReg
&= Control_CNT0
;
859 if ((devpriv
->ai_flags
& TRIG_WAKE_EOS
)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
862 devpriv
->CntrlReg
|= Control_ONEFH
;
866 if ((devpriv
->ai_scans
== 0) || (devpriv
->ai_scans
== -1)) {
867 devpriv
->neverending_ai
= 1;
868 } /* well, user want neverending */
870 devpriv
->neverending_ai
= 0;
875 if (devpriv
->ai_timer1
< this_board
->ai_ns_min
)
876 devpriv
->ai_timer1
= this_board
->ai_ns_min
;
877 devpriv
->CntrlReg
|= Control_PACER
| Control_IRQEN
;
879 devpriv
->ai_et_CntrlReg
= devpriv
->CntrlReg
;
881 ~(Control_PACER
| Control_ONEFH
| Control_GATE
);
882 devpriv
->CntrlReg
|= Control_EXT
;
887 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
888 &divisor2
, &devpriv
->ai_timer1
,
889 devpriv
->ai_flags
& TRIG_ROUND_MASK
);
891 ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
892 devpriv
->i8254_osc_base
, divisor1
, divisor2
,
894 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
897 start_pacer(dev
, mode
, divisor1
, divisor2
);
899 devpriv
->ai_et_div1
= divisor1
;
900 devpriv
->ai_et_div2
= divisor2
;
904 devpriv
->CntrlReg
|= Control_EXT
| Control_IRQEN
;
905 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
909 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
913 #ifdef PCI171X_EXTDEBUG
915 ==============================================================================
917 static void pci171x_cmdtest_out(int e
, struct comedi_cmd
*cmd
)
919 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e
,
920 cmd
->start_src
, cmd
->scan_begin_src
, cmd
->convert_src
);
921 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e
,
922 cmd
->start_arg
, cmd
->scan_begin_arg
, cmd
->convert_arg
);
923 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e
, cmd
->stop_src
,
925 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
926 e
, cmd
->stop_arg
, cmd
->scan_end_arg
, cmd
->chanlist_len
);
931 ==============================================================================
933 static int pci171x_ai_cmdtest(struct comedi_device
*dev
,
934 struct comedi_subdevice
*s
,
935 struct comedi_cmd
*cmd
)
938 int tmp
, divisor1
= 0, divisor2
= 0;
940 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
941 #ifdef PCI171X_EXTDEBUG
942 pci171x_cmdtest_out(-1, cmd
);
944 /* step 1: make sure trigger sources are trivially valid */
946 tmp
= cmd
->start_src
;
947 cmd
->start_src
&= TRIG_NOW
| TRIG_EXT
;
948 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
951 tmp
= cmd
->scan_begin_src
;
952 cmd
->scan_begin_src
&= TRIG_FOLLOW
;
953 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
956 tmp
= cmd
->convert_src
;
957 cmd
->convert_src
&= TRIG_TIMER
| TRIG_EXT
;
958 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
961 tmp
= cmd
->scan_end_src
;
962 cmd
->scan_end_src
&= TRIG_COUNT
;
963 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
967 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
968 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
972 #ifdef PCI171X_EXTDEBUG
973 pci171x_cmdtest_out(1, cmd
);
976 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
981 /* step 2: make sure trigger sources are unique and mutually compatible */
983 if (cmd
->start_src
!= TRIG_NOW
&& cmd
->start_src
!= TRIG_EXT
) {
984 cmd
->start_src
= TRIG_NOW
;
988 if (cmd
->scan_begin_src
!= TRIG_FOLLOW
) {
989 cmd
->scan_begin_src
= TRIG_FOLLOW
;
993 if (cmd
->convert_src
!= TRIG_TIMER
&& cmd
->convert_src
!= TRIG_EXT
)
996 if (cmd
->scan_end_src
!= TRIG_COUNT
) {
997 cmd
->scan_end_src
= TRIG_COUNT
;
1001 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
1005 #ifdef PCI171X_EXTDEBUG
1006 pci171x_cmdtest_out(2, cmd
);
1009 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1014 /* step 3: make sure arguments are trivially compatible */
1016 if (cmd
->start_arg
!= 0) {
1021 if (cmd
->scan_begin_arg
!= 0) {
1022 cmd
->scan_begin_arg
= 0;
1026 if (cmd
->convert_src
== TRIG_TIMER
) {
1027 if (cmd
->convert_arg
< this_board
->ai_ns_min
) {
1028 cmd
->convert_arg
= this_board
->ai_ns_min
;
1031 } else { /* TRIG_FOLLOW */
1032 if (cmd
->convert_arg
!= 0) {
1033 cmd
->convert_arg
= 0;
1038 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1039 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1042 if (cmd
->stop_src
== TRIG_COUNT
) {
1043 if (!cmd
->stop_arg
) {
1047 } else { /* TRIG_NONE */
1048 if (cmd
->stop_arg
!= 0) {
1055 #ifdef PCI171X_EXTDEBUG
1056 pci171x_cmdtest_out(3, cmd
);
1059 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1064 /* step 4: fix up any arguments */
1066 if (cmd
->convert_src
== TRIG_TIMER
) {
1067 tmp
= cmd
->convert_arg
;
1068 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
1069 &divisor2
, &cmd
->convert_arg
,
1070 cmd
->flags
& TRIG_ROUND_MASK
);
1071 if (cmd
->convert_arg
< this_board
->ai_ns_min
)
1072 cmd
->convert_arg
= this_board
->ai_ns_min
;
1073 if (tmp
!= cmd
->convert_arg
)
1079 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1084 /* step 5: complain about special chanlist considerations */
1086 if (cmd
->chanlist
) {
1087 if (!check_channel_list(dev
, s
, cmd
->chanlist
,
1089 return 5; /* incorrect channels list */
1092 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1097 ==============================================================================
1099 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1101 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1103 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1104 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
1105 devpriv
->ai_chanlist
= cmd
->chanlist
;
1106 devpriv
->ai_flags
= cmd
->flags
;
1107 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
1108 devpriv
->ai_data
= s
->async
->prealloc_buf
;
1109 devpriv
->ai_timer1
= 0;
1110 devpriv
->ai_timer2
= 0;
1112 if (cmd
->stop_src
== TRIG_COUNT
) {
1113 devpriv
->ai_scans
= cmd
->stop_arg
;
1115 devpriv
->ai_scans
= 0;
1118 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) { /* mode 1, 2, 3 */
1119 if (cmd
->convert_src
== TRIG_TIMER
) { /* mode 1 and 2 */
1120 devpriv
->ai_timer1
= cmd
->convert_arg
;
1121 return pci171x_ai_docmd_and_mode(cmd
->start_src
==
1122 TRIG_EXT
? 2 : 1, dev
,
1125 if (cmd
->convert_src
== TRIG_EXT
) { /* mode 3 */
1126 return pci171x_ai_docmd_and_mode(3, dev
, s
);
1134 ==============================================================================
1135 Check if channel list from user is builded correctly
1136 If it's ok, then program scan/gain logic.
1137 This works for all cards.
1139 static int check_channel_list(struct comedi_device
*dev
,
1140 struct comedi_subdevice
*s
,
1141 unsigned int *chanlist
, unsigned int n_chan
)
1143 unsigned int chansegment
[32];
1144 unsigned int i
, nowmustbechan
, seglen
, segpos
;
1146 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan
);
1147 /* correct channel and range number check itself comedi/range.c */
1149 comedi_error(dev
, "range/channel list is empty!");
1154 chansegment
[0] = chanlist
[0]; /* first channel is everytime ok */
1155 for (i
= 1, seglen
= 1; i
< n_chan
; i
++, seglen
++) { /* build part of chanlist */
1156 /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1157 if (chanlist
[0] == chanlist
[i
])
1158 break; /* we detect loop, this must by finish */
1159 if (CR_CHAN(chanlist
[i
]) & 1) /* odd channel cann't by differencial */
1160 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
) {
1162 "Odd channel can't be differential input!\n");
1166 (CR_CHAN(chansegment
[i
- 1]) + 1) % s
->n_chan
;
1167 if (CR_AREF(chansegment
[i
- 1]) == AREF_DIFF
)
1168 nowmustbechan
= (nowmustbechan
+ 1) % s
->n_chan
;
1169 if (nowmustbechan
!= CR_CHAN(chanlist
[i
])) { /* channel list isn't continous :-( */
1171 ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1172 i
, CR_CHAN(chanlist
[i
]), nowmustbechan
,
1173 CR_CHAN(chanlist
[0]));
1176 chansegment
[i
] = chanlist
[i
]; /* well, this is next correct channel in list */
1179 for (i
= 0, segpos
= 0; i
< n_chan
; i
++) { /* check whole chanlist */
1180 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1181 if (chanlist
[i
] != chansegment
[i
% seglen
]) {
1183 ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1184 i
, CR_CHAN(chansegment
[i
]),
1185 CR_RANGE(chansegment
[i
]),
1186 CR_AREF(chansegment
[i
]),
1187 CR_CHAN(chanlist
[i
% seglen
]),
1188 CR_RANGE(chanlist
[i
% seglen
]),
1189 CR_AREF(chansegment
[i
% seglen
]));
1190 return 0; /* chan/gain list is strange */
1199 static void setup_channel_list(struct comedi_device
*dev
,
1200 struct comedi_subdevice
*s
,
1201 unsigned int *chanlist
, unsigned int n_chan
,
1202 unsigned int seglen
)
1204 unsigned int i
, range
, chanprog
;
1206 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan
,
1208 devpriv
->act_chanlist_len
= seglen
;
1209 devpriv
->act_chanlist_pos
= 0;
1211 DPRINTK("SegLen: %d\n", seglen
);
1212 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
1213 chanprog
= muxonechan
[CR_CHAN(chanlist
[i
])];
1214 outw(chanprog
, dev
->iobase
+ PCI171x_MUX
); /* select channel */
1215 range
= this_board
->rangecode_ai
[CR_RANGE(chanlist
[i
])];
1216 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
)
1218 outw(range
, dev
->iobase
+ PCI171x_RANGE
); /* select gain */
1219 #ifdef PCI171x_PARANOIDCHECK
1220 devpriv
->act_chanlist
[i
] =
1221 (CR_CHAN(chanlist
[i
]) << 12) & 0xf000;
1223 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i
, chanprog
, range
,
1224 devpriv
->act_chanlist
[i
]);
1226 #ifdef PCI171x_PARANOIDCHECK
1227 for ( ; i
< n_chan
; i
++) { /* store remainder of channel list */
1228 devpriv
->act_chanlist
[i
] =
1229 (CR_CHAN(chanlist
[i
]) << 12) & 0xf000;
1233 devpriv
->ai_et_MuxVal
=
1234 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8);
1235 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
); /* select channel interval to scan */
1236 DPRINTK("MUX: %4x L%4x.H%4x\n",
1237 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8),
1238 CR_CHAN(chanlist
[0]), CR_CHAN(chanlist
[seglen
- 1]));
1242 ==============================================================================
1244 static void start_pacer(struct comedi_device
*dev
, int mode
,
1245 unsigned int divisor1
, unsigned int divisor2
)
1247 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode
,
1248 divisor1
, divisor2
);
1249 outw(0xb4, dev
->iobase
+ PCI171x_CNTCTRL
);
1250 outw(0x74, dev
->iobase
+ PCI171x_CNTCTRL
);
1253 outw(divisor2
& 0xff, dev
->iobase
+ PCI171x_CNT2
);
1254 outw((divisor2
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT2
);
1255 outw(divisor1
& 0xff, dev
->iobase
+ PCI171x_CNT1
);
1256 outw((divisor1
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT1
);
1258 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1262 ==============================================================================
1264 static int pci171x_ai_cancel(struct comedi_device
*dev
,
1265 struct comedi_subdevice
*s
)
1267 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1269 switch (this_board
->cardtype
) {
1271 devpriv
->CntrlReg
&= Control_CNT0
;
1272 devpriv
->CntrlReg
|= Control_SW
;
1274 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1275 start_pacer(dev
, -1, 0, 0);
1276 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
1277 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
1282 devpriv
->ai_act_scan
= 0;
1283 s
->async
->cur_chan
= 0;
1284 devpriv
->ai_buf_ptr
= 0;
1285 devpriv
->neverending_ai
= 0;
1287 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1292 ==============================================================================
1294 static int pci171x_reset(struct comedi_device
*dev
)
1296 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1297 outw(0x30, dev
->iobase
+ PCI171x_CNTCTRL
);
1298 devpriv
->CntrlReg
= Control_SW
| Control_CNT0
; /* Software trigger, CNT0=external */
1299 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1300 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1301 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1302 start_pacer(dev
, -1, 0, 0); /* stop 8254 */
1303 devpriv
->da_ranges
= 0;
1304 if (this_board
->n_aochan
) {
1305 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
); /* set DACs to 0..5V */
1306 outw(0, dev
->iobase
+ PCI171x_DA1
); /* set DA outputs to 0V */
1307 devpriv
->ao_data
[0] = 0x0000;
1308 if (this_board
->n_aochan
> 1) {
1309 outw(0, dev
->iobase
+ PCI171x_DA2
);
1310 devpriv
->ao_data
[1] = 0x0000;
1313 outw(0, dev
->iobase
+ PCI171x_DO
); /* digital outputs to 0 */
1314 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1315 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1317 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1322 ==============================================================================
1324 static int pci1720_reset(struct comedi_device
*dev
)
1326 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1327 outb(Syncont_SC0
, dev
->iobase
+ PCI1720_SYNCONT
); /* set synchronous output mode */
1328 devpriv
->da_ranges
= 0xAA;
1329 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI1720_RANGE
); /* set all ranges to +/-5V */
1330 outw(0x0800, dev
->iobase
+ PCI1720_DA0
); /* set outputs to 0V */
1331 outw(0x0800, dev
->iobase
+ PCI1720_DA1
);
1332 outw(0x0800, dev
->iobase
+ PCI1720_DA2
);
1333 outw(0x0800, dev
->iobase
+ PCI1720_DA3
);
1334 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
1335 devpriv
->ao_data
[0] = 0x0800;
1336 devpriv
->ao_data
[1] = 0x0800;
1337 devpriv
->ao_data
[2] = 0x0800;
1338 devpriv
->ao_data
[3] = 0x0800;
1339 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1344 ==============================================================================
1346 static int pci1710_reset(struct comedi_device
*dev
)
1348 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1349 switch (this_board
->cardtype
) {
1351 return pci1720_reset(dev
);
1353 return pci171x_reset(dev
);
1355 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1359 ==============================================================================
1361 static int pci1710_attach(struct comedi_device
*dev
,
1362 struct comedi_devconfig
*it
)
1364 struct comedi_subdevice
*s
;
1365 int ret
, subdev
, n_subdevices
;
1367 unsigned long iobase
;
1368 struct pci_dev
*pcidev
;
1369 int opt_bus
, opt_slot
;
1371 unsigned char pci_bus
, pci_slot
, pci_func
;
1375 printk("comedi%d: adv_pci1710: ", dev
->minor
);
1377 opt_bus
= it
->options
[0];
1378 opt_slot
= it
->options
[1];
1380 ret
= alloc_private(dev
, sizeof(struct pci1710_private
));
1382 printk(" - Allocation failed!\n");
1386 /* Look for matching PCI device */
1387 errstr
= "not found!";
1389 board_index
= this_board
- boardtypes
;
1390 while (NULL
!= (pcidev
= pci_get_device(PCI_VENDOR_ID_ADVANTECH
,
1391 PCI_ANY_ID
, pcidev
))) {
1392 if (strcmp(this_board
->name
, DRV_NAME
) == 0) {
1393 for (i
= 0; i
< n_boardtypes
; ++i
) {
1394 if (pcidev
->device
== boardtypes
[i
].device_id
) {
1399 if (i
== n_boardtypes
)
1402 if (pcidev
->device
!= boardtypes
[board_index
].device_id
)
1406 /* Found matching vendor/device. */
1407 if (opt_bus
|| opt_slot
) {
1408 /* Check bus/slot. */
1409 if (opt_bus
!= pcidev
->bus
->number
1410 || opt_slot
!= PCI_SLOT(pcidev
->devfn
))
1411 continue; /* no match */
1414 * Look for device that isn't in use.
1415 * Enable PCI device and request regions.
1417 if (comedi_pci_enable(pcidev
, DRV_NAME
)) {
1419 "failed to enable PCI device and request regions!";
1422 /* fixup board_ptr in case we were using the dummy entry with the driver name */
1423 dev
->board_ptr
= &boardtypes
[board_index
];
1428 if (opt_bus
|| opt_slot
) {
1429 printk(" - Card at b:s %d:%d %s\n",
1430 opt_bus
, opt_slot
, errstr
);
1432 printk(" - Card %s\n", errstr
);
1437 pci_bus
= pcidev
->bus
->number
;
1438 pci_slot
= PCI_SLOT(pcidev
->devfn
);
1439 pci_func
= PCI_FUNC(pcidev
->devfn
);
1441 iobase
= pci_resource_start(pcidev
, 2);
1443 printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus
, pci_slot
, pci_func
,
1446 dev
->iobase
= iobase
;
1448 dev
->board_name
= this_board
->name
;
1449 devpriv
->pcidev
= pcidev
;
1452 if (this_board
->n_aichan
)
1454 if (this_board
->n_aochan
)
1456 if (this_board
->n_dichan
)
1458 if (this_board
->n_dochan
)
1460 if (this_board
->n_counter
)
1463 ret
= alloc_subdevices(dev
, n_subdevices
);
1465 printk(" - Allocation failed!\n");
1471 if (this_board
->have_irq
) {
1473 if (request_irq(irq
, interrupt_service_pci1710
,
1474 IRQF_SHARED
, "Advantech PCI-1710",
1477 (", unable to allocate IRQ %d, DISABLING IT",
1479 irq
= 0; /* Can't use IRQ */
1481 printk(", irq=%u", irq
);
1484 printk(", IRQ disabled");
1496 if (this_board
->n_aichan
) {
1497 s
= dev
->subdevices
+ subdev
;
1498 dev
->read_subdev
= s
;
1499 s
->type
= COMEDI_SUBD_AI
;
1500 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
1501 if (this_board
->n_aichand
)
1502 s
->subdev_flags
|= SDF_DIFF
;
1503 s
->n_chan
= this_board
->n_aichan
;
1504 s
->maxdata
= this_board
->ai_maxdata
;
1505 s
->len_chanlist
= this_board
->n_aichan
;
1506 s
->range_table
= this_board
->rangelist_ai
;
1507 s
->cancel
= pci171x_ai_cancel
;
1508 s
->insn_read
= pci171x_insn_read_ai
;
1510 s
->subdev_flags
|= SDF_CMD_READ
;
1511 s
->do_cmdtest
= pci171x_ai_cmdtest
;
1512 s
->do_cmd
= pci171x_ai_cmd
;
1514 devpriv
->i8254_osc_base
= 100; /* 100ns=10MHz */
1518 if (this_board
->n_aochan
) {
1519 s
= dev
->subdevices
+ subdev
;
1520 s
->type
= COMEDI_SUBD_AO
;
1521 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1522 s
->n_chan
= this_board
->n_aochan
;
1523 s
->maxdata
= this_board
->ao_maxdata
;
1524 s
->len_chanlist
= this_board
->n_aochan
;
1525 s
->range_table
= this_board
->rangelist_ao
;
1526 switch (this_board
->cardtype
) {
1528 s
->insn_write
= pci1720_insn_write_ao
;
1531 s
->insn_write
= pci171x_insn_write_ao
;
1534 s
->insn_read
= pci171x_insn_read_ao
;
1538 if (this_board
->n_dichan
) {
1539 s
= dev
->subdevices
+ subdev
;
1540 s
->type
= COMEDI_SUBD_DI
;
1541 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_COMMON
;
1542 s
->n_chan
= this_board
->n_dichan
;
1544 s
->len_chanlist
= this_board
->n_dichan
;
1545 s
->range_table
= &range_digital
;
1546 s
->io_bits
= 0; /* all bits input */
1547 s
->insn_bits
= pci171x_insn_bits_di
;
1551 if (this_board
->n_dochan
) {
1552 s
= dev
->subdevices
+ subdev
;
1553 s
->type
= COMEDI_SUBD_DO
;
1554 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1555 s
->n_chan
= this_board
->n_dochan
;
1557 s
->len_chanlist
= this_board
->n_dochan
;
1558 s
->range_table
= &range_digital
;
1559 s
->io_bits
= (1 << this_board
->n_dochan
) - 1; /* all bits output */
1561 s
->insn_bits
= pci171x_insn_bits_do
;
1565 if (this_board
->n_counter
) {
1566 s
= dev
->subdevices
+ subdev
;
1567 s
->type
= COMEDI_SUBD_COUNTER
;
1568 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
1569 s
->n_chan
= this_board
->n_counter
;
1570 s
->len_chanlist
= this_board
->n_counter
;
1571 s
->maxdata
= 0xffff;
1572 s
->range_table
= &range_unknown
;
1573 s
->insn_read
= pci171x_insn_counter_read
;
1574 s
->insn_write
= pci171x_insn_counter_write
;
1575 s
->insn_config
= pci171x_insn_counter_config
;
1585 ==============================================================================
1587 static int pci1710_detach(struct comedi_device
*dev
)
1594 free_irq(dev
->irq
, dev
);
1595 if (devpriv
->pcidev
) {
1597 comedi_pci_disable(devpriv
->pcidev
);
1599 pci_dev_put(devpriv
->pcidev
);
1607 ==============================================================================
1609 COMEDI_PCI_INITCLEANUP(driver_pci1710
, pci1710_pci_table
);
1611 ==============================================================================