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 #define PCI_VENDOR_ID_ADVANTECH 0x13fe
68 /* hardware types of the cards */
69 #define TYPE_PCI171X 0
70 #define TYPE_PCI1713 2
71 #define TYPE_PCI1720 3
73 #define IORANGE_171x 32
74 #define IORANGE_1720 16
76 #define PCI171x_AD_DATA 0 /* R: A/D data */
77 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
78 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
79 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
80 #define PCI171x_STATUS 6 /* R: status register */
81 #define PCI171x_CONTROL 6 /* W: control register */
82 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
83 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
84 #define PCI171x_DA1 10 /* W: D/A register */
85 #define PCI171x_DA2 12 /* W: D/A register */
86 #define PCI171x_DAREF 14 /* W: D/A reference control */
87 #define PCI171x_DI 16 /* R: digi inputs */
88 #define PCI171x_DO 16 /* R: digi inputs */
89 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
90 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
91 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
92 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
94 /* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */
95 #define Status_FE 0x0100 /* 1=FIFO is empty */
96 #define Status_FH 0x0200 /* 1=FIFO is half full */
97 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
98 #define Status_IRQ 0x0800 /* 1=IRQ occured */
99 /* bits from control register (PCI171x_CONTROL) */
100 #define Control_CNT0 0x0040 /* 1=CNT0 have external source, 0=have internal 100kHz source */
101 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
102 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
103 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
104 #define Control_EXT 0x0004 /* 1=external trigger source */
105 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
106 #define Control_SW 0x0001 /* 1=enable software trigger source */
107 /* bits from counter control register (PCI171x_CNTCTRL) */
108 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
109 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
110 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
111 #define Counter_M2 0x0008
112 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
113 #define Counter_RW1 0x0020
114 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
115 #define Counter_SC1 0x0080 /* be used, 00 for CNT0, 11 for read-back command */
117 #define PCI1720_DA0 0 /* W: D/A register 0 */
118 #define PCI1720_DA1 2 /* W: D/A register 1 */
119 #define PCI1720_DA2 4 /* W: D/A register 2 */
120 #define PCI1720_DA3 6 /* W: D/A register 3 */
121 #define PCI1720_RANGE 8 /* R/W: D/A range register */
122 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
123 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
125 /* D/A synchronized control (PCI1720_SYNCONT) */
126 #define Syncont_SC0 1 /* set synchronous output mode */
128 static const struct comedi_lrange range_pci1710_3
= { 9, {
141 static const char range_codes_pci1710_3
[] =
142 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 };
144 static const struct comedi_lrange range_pci1710hg
= { 12, {
160 static const char range_codes_pci1710hg
[] =
161 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12,
165 static const struct comedi_lrange range_pci17x1
= { 5, {
174 static const char range_codes_pci17x1
[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
176 static const struct comedi_lrange range_pci1720
= { 4, {
184 static const struct comedi_lrange range_pci171x_da
= { 2, {
190 static int pci1710_attach(struct comedi_device
*dev
,
191 struct comedi_devconfig
*it
);
192 static int pci1710_detach(struct comedi_device
*dev
);
195 const char *name
; /* board name */
197 int iorange
; /* I/O range len */
198 char have_irq
; /* 1=card support IRQ */
199 char cardtype
; /* 0=1710& co. 2=1713, ... */
200 int n_aichan
; /* num of A/D chans */
201 int n_aichand
; /* num of A/D chans in diff mode */
202 int n_aochan
; /* num of D/A chans */
203 int n_dichan
; /* num of DI chans */
204 int n_dochan
; /* num of DO chans */
205 int n_counter
; /* num of counters */
206 int ai_maxdata
; /* resolution of A/D */
207 int ao_maxdata
; /* resolution of D/A */
208 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
209 const char *rangecode_ai
; /* range codes for programming */
210 const struct comedi_lrange
*rangelist_ao
; /* rangelist for D/A */
211 unsigned int ai_ns_min
; /* max sample speed of card v ns */
212 unsigned int fifo_half_size
; /* size of FIFO/2 */
215 static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table
) = {
217 PCI_VENDOR_ID_ADVANTECH
, 0x1710, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
218 PCI_VENDOR_ID_ADVANTECH
, 0x1711, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
219 PCI_VENDOR_ID_ADVANTECH
, 0x1713, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
220 PCI_VENDOR_ID_ADVANTECH
, 0x1720, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
221 PCI_VENDOR_ID_ADVANTECH
, 0x1731, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0}, {
225 MODULE_DEVICE_TABLE(pci
, pci1710_pci_table
);
227 static const struct boardtype boardtypes
[] = {
229 IORANGE_171x
, 1, TYPE_PCI171X
,
230 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
231 &range_pci1710_3
, range_codes_pci1710_3
,
234 {"pci1710hg", 0x1710,
235 IORANGE_171x
, 1, TYPE_PCI171X
,
236 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
237 &range_pci1710hg
, range_codes_pci1710hg
,
241 IORANGE_171x
, 1, TYPE_PCI171X
,
242 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
243 &range_pci17x1
, range_codes_pci17x1
, &range_pci171x_da
,
246 IORANGE_171x
, 1, TYPE_PCI1713
,
247 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
248 &range_pci1710_3
, range_codes_pci1710_3
, NULL
,
251 IORANGE_1720
, 0, TYPE_PCI1720
,
252 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
253 NULL
, NULL
, &range_pci1720
,
256 IORANGE_171x
, 1, TYPE_PCI171X
,
257 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
258 &range_pci17x1
, range_codes_pci17x1
, NULL
,
260 /* dummy entry corresponding to driver name */
264 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
266 static struct comedi_driver driver_pci1710
= {
267 .driver_name
= DRV_NAME
,
268 .module
= THIS_MODULE
,
269 .attach
= pci1710_attach
,
270 .detach
= pci1710_detach
,
271 .num_names
= n_boardtypes
,
272 .board_name
= &boardtypes
[0].name
,
273 .offset
= sizeof(struct boardtype
),
276 struct pci1710_private
{
277 struct pci_dev
*pcidev
; /* ptr to PCI device */
278 char valid
; /* card is usable */
279 char neverending_ai
; /* we do unlimited AI */
280 unsigned int CntrlReg
; /* Control register */
281 unsigned int i8254_osc_base
; /* frequence of onboard oscilator */
282 unsigned int ai_do
; /* what do AI? 0=nothing, 1 to 4 mode */
283 unsigned int ai_act_scan
; /* how many scans we finished */
284 unsigned int ai_act_chan
; /* actual position in actual scan */
285 unsigned int ai_buf_ptr
; /* data buffer ptr in samples */
286 unsigned char ai_eos
; /* 1=EOS wake up */
288 unsigned int ai_et_CntrlReg
;
289 unsigned int ai_et_MuxVal
;
290 unsigned int ai_et_div1
, ai_et_div2
;
291 unsigned int act_chanlist
[32]; /* list of scaned channel */
292 unsigned char act_chanlist_len
; /* len of scanlist */
293 unsigned char act_chanlist_pos
; /* actual position in MUX list */
294 unsigned char da_ranges
; /* copy of D/A outpit range register */
295 unsigned int ai_scans
; /* len of scanlist */
296 unsigned int ai_n_chan
; /* how many channels is measured */
297 unsigned int *ai_chanlist
; /* actaul chanlist */
298 unsigned int ai_flags
; /* flaglist */
299 unsigned int ai_data_len
; /* len of data buffer */
300 short *ai_data
; /* data buffer */
301 unsigned int ai_timer1
; /* timers */
302 unsigned int ai_timer2
;
303 short ao_data
[4]; /* data output buffer */
304 unsigned int cnt0_write_wait
; /* after a write, wait for update of the internal state */
307 #define devpriv ((struct pci1710_private *)dev->private)
308 #define this_board ((const struct boardtype *)dev->board_ptr)
311 ==============================================================================
314 static int check_channel_list(struct comedi_device
*dev
,
315 struct comedi_subdevice
*s
,
316 unsigned int *chanlist
, unsigned int n_chan
);
317 static void setup_channel_list(struct comedi_device
*dev
,
318 struct comedi_subdevice
*s
,
319 unsigned int *chanlist
, unsigned int n_chan
,
320 unsigned int seglen
);
321 static void start_pacer(struct comedi_device
*dev
, int mode
,
322 unsigned int divisor1
, unsigned int divisor2
);
323 static int pci1710_reset(struct comedi_device
*dev
);
324 static int pci171x_ai_cancel(struct comedi_device
*dev
,
325 struct comedi_subdevice
*s
);
327 static const unsigned int muxonechan
[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */
328 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
329 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
330 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
334 ==============================================================================
336 static int pci171x_insn_read_ai(struct comedi_device
*dev
,
337 struct comedi_subdevice
*s
,
338 struct comedi_insn
*insn
, unsigned int *data
)
341 #ifdef PCI171x_PARANOIDCHECK
345 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
346 devpriv
->CntrlReg
&= Control_CNT0
;
347 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
348 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
349 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
350 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
352 setup_channel_list(dev
, s
, &insn
->chanspec
, 1, 1);
354 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
355 inw(dev
->iobase
+ PCI171x_STATUS
),
356 dev
->iobase
+ PCI171x_STATUS
);
357 for (n
= 0; n
< insn
->n
; n
++) {
358 outw(0, dev
->iobase
+ PCI171x_SOFTTRG
); /* start conversion */
359 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n
,
360 inw(dev
->iobase
+ PCI171x_STATUS
));
362 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n
,
363 inw(dev
->iobase
+ PCI171x_STATUS
));
366 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
))
369 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n
,
371 inw(dev
->iobase
+ PCI171x_STATUS
));
373 comedi_error(dev
, "A/D insn timeout");
374 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
375 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
378 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
383 #ifdef PCI171x_PARANOIDCHECK
384 idata
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
385 if (this_board
->cardtype
!= TYPE_PCI1713
)
386 if ((idata
& 0xf000) != devpriv
->act_chanlist
[0]) {
387 comedi_error(dev
, "A/D insn data droput!");
390 data
[n
] = idata
& 0x0fff;
392 data
[n
] = inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff;
397 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
398 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
400 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n
);
405 ==============================================================================
407 static int pci171x_insn_write_ao(struct comedi_device
*dev
,
408 struct comedi_subdevice
*s
,
409 struct comedi_insn
*insn
, unsigned int *data
)
411 int n
, chan
, range
, ofs
;
413 chan
= CR_CHAN(insn
->chanspec
);
414 range
= CR_RANGE(insn
->chanspec
);
416 devpriv
->da_ranges
&= 0xfb;
417 devpriv
->da_ranges
|= (range
<< 2);
418 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
421 devpriv
->da_ranges
&= 0xfe;
422 devpriv
->da_ranges
|= range
;
423 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
427 for (n
= 0; n
< insn
->n
; n
++)
428 outw(data
[n
], dev
->iobase
+ ofs
);
430 devpriv
->ao_data
[chan
] = data
[n
];
437 ==============================================================================
439 static int pci171x_insn_read_ao(struct comedi_device
*dev
,
440 struct comedi_subdevice
*s
,
441 struct comedi_insn
*insn
, unsigned int *data
)
445 chan
= CR_CHAN(insn
->chanspec
);
446 for (n
= 0; n
< insn
->n
; n
++)
447 data
[n
] = devpriv
->ao_data
[chan
];
453 ==============================================================================
455 static int pci171x_insn_bits_di(struct comedi_device
*dev
,
456 struct comedi_subdevice
*s
,
457 struct comedi_insn
*insn
, unsigned int *data
)
459 data
[1] = inw(dev
->iobase
+ PCI171x_DI
);
465 ==============================================================================
467 static int pci171x_insn_bits_do(struct comedi_device
*dev
,
468 struct comedi_subdevice
*s
,
469 struct comedi_insn
*insn
, unsigned int *data
)
472 s
->state
&= ~data
[0];
473 s
->state
|= (data
[0] & data
[1]);
474 outw(s
->state
, dev
->iobase
+ PCI171x_DO
);
482 ==============================================================================
484 static int pci171x_insn_counter_read(struct comedi_device
*dev
,
485 struct comedi_subdevice
*s
,
486 struct comedi_insn
*insn
,
489 unsigned int msb
, lsb
, ccntrl
;
492 ccntrl
= 0xD2; /* count only */
493 for (i
= 0; i
< insn
->n
; i
++) {
494 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
496 lsb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
497 msb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
499 data
[0] = lsb
| (msb
<< 8);
506 ==============================================================================
508 static int pci171x_insn_counter_write(struct comedi_device
*dev
,
509 struct comedi_subdevice
*s
,
510 struct comedi_insn
*insn
,
513 uint msb
, lsb
, ccntrl
, status
;
515 lsb
= data
[0] & 0x00FF;
516 msb
= (data
[0] & 0xFF00) >> 8;
518 /* write lsb, then msb */
519 outw(lsb
, dev
->iobase
+ PCI171x_CNT0
);
520 outw(msb
, dev
->iobase
+ PCI171x_CNT0
);
522 if (devpriv
->cnt0_write_wait
) {
523 /* wait for the new count to be loaded */
526 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
527 status
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
528 } while (status
& 0x40);
535 ==============================================================================
537 static int pci171x_insn_counter_config(struct comedi_device
*dev
,
538 struct comedi_subdevice
*s
,
539 struct comedi_insn
*insn
,
543 /* This doesn't work like a normal Comedi counter config */
546 devpriv
->cnt0_write_wait
= data
[0] & 0x20;
548 /* internal or external clock? */
549 if (!(data
[0] & 0x10)) { /* internal */
550 devpriv
->CntrlReg
&= ~Control_CNT0
;
552 devpriv
->CntrlReg
|= Control_CNT0
;
554 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
557 ccntrl
|= Counter_M0
;
559 ccntrl
|= Counter_M1
;
561 ccntrl
|= Counter_M2
;
563 ccntrl
|= Counter_BCD
;
564 ccntrl
|= Counter_RW0
; /* set read/write mode */
565 ccntrl
|= Counter_RW1
;
566 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
573 ==============================================================================
575 static int pci1720_insn_write_ao(struct comedi_device
*dev
,
576 struct comedi_subdevice
*s
,
577 struct comedi_insn
*insn
, unsigned int *data
)
579 int n
, rangereg
, chan
;
581 chan
= CR_CHAN(insn
->chanspec
);
582 rangereg
= devpriv
->da_ranges
& (~(0x03 << (chan
<< 1)));
583 rangereg
|= (CR_RANGE(insn
->chanspec
) << (chan
<< 1));
584 if (rangereg
!= devpriv
->da_ranges
) {
585 outb(rangereg
, dev
->iobase
+ PCI1720_RANGE
);
586 devpriv
->da_ranges
= rangereg
;
589 for (n
= 0; n
< insn
->n
; n
++) {
590 outw(data
[n
], dev
->iobase
+ PCI1720_DA0
+ (chan
<< 1));
591 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
594 devpriv
->ao_data
[chan
] = data
[n
];
600 ==============================================================================
602 static void interrupt_pci1710_every_sample(void *d
)
604 struct comedi_device
*dev
= d
;
605 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
607 #ifdef PCI171x_PARANOIDCHECK
611 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
612 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
614 printk("comedi%d: A/D FIFO empty (%4x)\n", dev
->minor
, m
);
615 pci171x_ai_cancel(dev
, s
);
616 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
617 comedi_event(dev
, s
);
622 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
624 pci171x_ai_cancel(dev
, s
);
625 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
626 comedi_event(dev
, s
);
630 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
633 for (; !(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
);) {
634 #ifdef PCI171x_PARANOIDCHECK
635 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
636 DPRINTK("%04x:", sampl
);
637 if (this_board
->cardtype
!= TYPE_PCI1713
)
638 if ((sampl
& 0xf000) !=
639 devpriv
->act_chanlist
[s
->async
->cur_chan
]) {
641 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
642 (sampl
& 0xf000) >> 12,
645 async
->cur_chan
] & 0xf000) >>
647 pci171x_ai_cancel(dev
, s
);
649 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
650 comedi_event(dev
, s
);
653 DPRINTK("%8d %2d %8d~", s
->async
->buf_int_ptr
,
654 s
->async
->cur_chan
, s
->async
->buf_int_count
);
655 comedi_buf_put(s
->async
, sampl
& 0x0fff);
657 comedi_buf_put(s
->async
,
658 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
660 ++s
->async
->cur_chan
;
662 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
)
663 s
->async
->cur_chan
= 0;
666 if (s
->async
->cur_chan
== 0) { /* one scan done */
667 devpriv
->ai_act_scan
++;
669 ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
670 s
->async
->buf_int_count
, s
->async
->buf_int_ptr
,
671 s
->async
->buf_user_count
, s
->async
->buf_user_ptr
);
672 DPRINTK("adv_pci1710 EDBG: EOS2\n");
673 if ((!devpriv
->neverending_ai
) && (devpriv
->ai_act_scan
>= devpriv
->ai_scans
)) { /* all data sampled */
674 pci171x_ai_cancel(dev
, s
);
675 s
->async
->events
|= COMEDI_CB_EOA
;
676 comedi_event(dev
, s
);
682 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
683 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
685 comedi_event(dev
, s
);
689 ==============================================================================
691 static int move_block_from_fifo(struct comedi_device
*dev
,
692 struct comedi_subdevice
*s
, int n
, int turn
)
695 #ifdef PCI171x_PARANOIDCHECK
698 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n
,
700 j
= s
->async
->cur_chan
;
701 for (i
= 0; i
< n
; i
++) {
702 #ifdef PCI171x_PARANOIDCHECK
703 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
704 if (this_board
->cardtype
!= TYPE_PCI1713
)
705 if ((sampl
& 0xf000) != devpriv
->act_chanlist
[j
]) {
707 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
708 dev
->minor
, (sampl
& 0xf000) >> 12,
709 (devpriv
->act_chanlist
[j
] & 0xf000) >> 12,
710 i
, j
, devpriv
->ai_act_scan
, n
, turn
,
712 pci171x_ai_cancel(dev
, s
);
714 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
715 comedi_event(dev
, s
);
718 comedi_buf_put(s
->async
, sampl
& 0x0fff);
720 comedi_buf_put(s
->async
,
721 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
724 if (j
>= devpriv
->ai_n_chan
) {
726 devpriv
->ai_act_scan
++;
729 s
->async
->cur_chan
= j
;
730 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
735 ==============================================================================
737 static void interrupt_pci1710_half_fifo(void *d
)
739 struct comedi_device
*dev
= d
;
740 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
743 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
744 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
745 if (!(m
& Status_FH
)) {
746 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
748 pci171x_ai_cancel(dev
, s
);
749 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
750 comedi_event(dev
, s
);
755 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
757 pci171x_ai_cancel(dev
, s
);
758 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
759 comedi_event(dev
, s
);
763 samplesinbuf
= this_board
->fifo_half_size
;
764 if (samplesinbuf
* sizeof(short) >= devpriv
->ai_data_len
) {
765 m
= devpriv
->ai_data_len
/ sizeof(short);
766 if (move_block_from_fifo(dev
, s
, m
, 0))
772 if (move_block_from_fifo(dev
, s
, samplesinbuf
, 1))
776 if (!devpriv
->neverending_ai
)
777 if (devpriv
->ai_act_scan
>= devpriv
->ai_scans
) { /* all data sampled */
778 pci171x_ai_cancel(dev
, s
);
779 s
->async
->events
|= COMEDI_CB_EOA
;
780 comedi_event(dev
, s
);
783 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
784 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
786 comedi_event(dev
, s
);
790 ==============================================================================
792 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
794 struct comedi_device
*dev
= d
;
796 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
798 if (!dev
->attached
) /* is device attached? */
799 return IRQ_NONE
; /* no, exit */
801 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_IRQ
)) /* is this interrupt from our board? */
802 return IRQ_NONE
; /* no, exit */
804 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
805 inw(dev
->iobase
+ PCI171x_STATUS
));
807 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
809 devpriv
->CntrlReg
&= Control_CNT0
;
810 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
811 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
812 devpriv
->CntrlReg
= devpriv
->ai_et_CntrlReg
;
813 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
814 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
815 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
);
816 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
818 start_pacer(dev
, 1, devpriv
->ai_et_div1
, devpriv
->ai_et_div2
);
821 if (devpriv
->ai_eos
) { /* We use FIFO half full INT or not? */
822 interrupt_pci1710_every_sample(d
);
824 interrupt_pci1710_half_fifo(d
);
826 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
831 ==============================================================================
833 static int pci171x_ai_docmd_and_mode(int mode
, struct comedi_device
*dev
,
834 struct comedi_subdevice
*s
)
836 unsigned int divisor1
= 0, divisor2
= 0;
839 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
841 start_pacer(dev
, -1, 0, 0); /* stop pacer */
843 seglen
= check_channel_list(dev
, s
, devpriv
->ai_chanlist
,
847 setup_channel_list(dev
, s
, devpriv
->ai_chanlist
,
848 devpriv
->ai_n_chan
, seglen
);
850 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
851 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
853 devpriv
->ai_do
= mode
;
855 devpriv
->ai_act_scan
= 0;
856 s
->async
->cur_chan
= 0;
857 devpriv
->ai_buf_ptr
= 0;
858 devpriv
->neverending_ai
= 0;
860 devpriv
->CntrlReg
&= Control_CNT0
;
861 if ((devpriv
->ai_flags
& TRIG_WAKE_EOS
)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
864 devpriv
->CntrlReg
|= Control_ONEFH
;
868 if ((devpriv
->ai_scans
== 0) || (devpriv
->ai_scans
== -1))
869 devpriv
->neverending_ai
= 1;
870 /* well, user want neverending */
872 devpriv
->neverending_ai
= 0;
877 if (devpriv
->ai_timer1
< this_board
->ai_ns_min
)
878 devpriv
->ai_timer1
= this_board
->ai_ns_min
;
879 devpriv
->CntrlReg
|= Control_PACER
| Control_IRQEN
;
881 devpriv
->ai_et_CntrlReg
= devpriv
->CntrlReg
;
883 ~(Control_PACER
| Control_ONEFH
| Control_GATE
);
884 devpriv
->CntrlReg
|= Control_EXT
;
889 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
890 &divisor2
, &devpriv
->ai_timer1
,
891 devpriv
->ai_flags
& TRIG_ROUND_MASK
);
893 ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
894 devpriv
->i8254_osc_base
, divisor1
, divisor2
,
896 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
899 start_pacer(dev
, mode
, divisor1
, divisor2
);
901 devpriv
->ai_et_div1
= divisor1
;
902 devpriv
->ai_et_div2
= divisor2
;
906 devpriv
->CntrlReg
|= Control_EXT
| Control_IRQEN
;
907 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
911 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
915 #ifdef PCI171X_EXTDEBUG
917 ==============================================================================
919 static void pci171x_cmdtest_out(int e
, struct comedi_cmd
*cmd
)
921 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e
,
922 cmd
->start_src
, cmd
->scan_begin_src
, cmd
->convert_src
);
923 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e
,
924 cmd
->start_arg
, cmd
->scan_begin_arg
, cmd
->convert_arg
);
925 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e
, cmd
->stop_src
,
927 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
928 e
, cmd
->stop_arg
, cmd
->scan_end_arg
, cmd
->chanlist_len
);
933 ==============================================================================
935 static int pci171x_ai_cmdtest(struct comedi_device
*dev
,
936 struct comedi_subdevice
*s
,
937 struct comedi_cmd
*cmd
)
941 unsigned int divisor1
= 0, divisor2
= 0;
943 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
944 #ifdef PCI171X_EXTDEBUG
945 pci171x_cmdtest_out(-1, cmd
);
947 /* step 1: make sure trigger sources are trivially valid */
949 tmp
= cmd
->start_src
;
950 cmd
->start_src
&= TRIG_NOW
| TRIG_EXT
;
951 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
954 tmp
= cmd
->scan_begin_src
;
955 cmd
->scan_begin_src
&= TRIG_FOLLOW
;
956 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
959 tmp
= cmd
->convert_src
;
960 cmd
->convert_src
&= TRIG_TIMER
| TRIG_EXT
;
961 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
964 tmp
= cmd
->scan_end_src
;
965 cmd
->scan_end_src
&= TRIG_COUNT
;
966 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
970 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
971 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
975 #ifdef PCI171X_EXTDEBUG
976 pci171x_cmdtest_out(1, cmd
);
979 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
984 /* step 2: make sure trigger sources are unique and mutually compatible */
986 if (cmd
->start_src
!= TRIG_NOW
&& cmd
->start_src
!= TRIG_EXT
) {
987 cmd
->start_src
= TRIG_NOW
;
991 if (cmd
->scan_begin_src
!= TRIG_FOLLOW
) {
992 cmd
->scan_begin_src
= TRIG_FOLLOW
;
996 if (cmd
->convert_src
!= TRIG_TIMER
&& cmd
->convert_src
!= TRIG_EXT
)
999 if (cmd
->scan_end_src
!= TRIG_COUNT
) {
1000 cmd
->scan_end_src
= TRIG_COUNT
;
1004 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
1008 #ifdef PCI171X_EXTDEBUG
1009 pci171x_cmdtest_out(2, cmd
);
1012 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1017 /* step 3: make sure arguments are trivially compatible */
1019 if (cmd
->start_arg
!= 0) {
1024 if (cmd
->scan_begin_arg
!= 0) {
1025 cmd
->scan_begin_arg
= 0;
1029 if (cmd
->convert_src
== TRIG_TIMER
) {
1030 if (cmd
->convert_arg
< this_board
->ai_ns_min
) {
1031 cmd
->convert_arg
= this_board
->ai_ns_min
;
1034 } else { /* TRIG_FOLLOW */
1035 if (cmd
->convert_arg
!= 0) {
1036 cmd
->convert_arg
= 0;
1041 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1042 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1045 if (cmd
->stop_src
== TRIG_COUNT
) {
1046 if (!cmd
->stop_arg
) {
1050 } else { /* TRIG_NONE */
1051 if (cmd
->stop_arg
!= 0) {
1058 #ifdef PCI171X_EXTDEBUG
1059 pci171x_cmdtest_out(3, cmd
);
1062 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1067 /* step 4: fix up any arguments */
1069 if (cmd
->convert_src
== TRIG_TIMER
) {
1070 tmp
= cmd
->convert_arg
;
1071 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
1072 &divisor2
, &cmd
->convert_arg
,
1073 cmd
->flags
& TRIG_ROUND_MASK
);
1074 if (cmd
->convert_arg
< this_board
->ai_ns_min
)
1075 cmd
->convert_arg
= this_board
->ai_ns_min
;
1076 if (tmp
!= cmd
->convert_arg
)
1082 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1087 /* step 5: complain about special chanlist considerations */
1089 if (cmd
->chanlist
) {
1090 if (!check_channel_list(dev
, s
, cmd
->chanlist
,
1092 return 5; /* incorrect channels list */
1095 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1100 ==============================================================================
1102 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1104 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1106 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1107 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
1108 devpriv
->ai_chanlist
= cmd
->chanlist
;
1109 devpriv
->ai_flags
= cmd
->flags
;
1110 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
1111 devpriv
->ai_data
= s
->async
->prealloc_buf
;
1112 devpriv
->ai_timer1
= 0;
1113 devpriv
->ai_timer2
= 0;
1115 if (cmd
->stop_src
== TRIG_COUNT
)
1116 devpriv
->ai_scans
= cmd
->stop_arg
;
1118 devpriv
->ai_scans
= 0;
1121 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) { /* mode 1, 2, 3 */
1122 if (cmd
->convert_src
== TRIG_TIMER
) { /* mode 1 and 2 */
1123 devpriv
->ai_timer1
= cmd
->convert_arg
;
1124 return pci171x_ai_docmd_and_mode(cmd
->start_src
==
1125 TRIG_EXT
? 2 : 1, dev
,
1128 if (cmd
->convert_src
== TRIG_EXT
) { /* mode 3 */
1129 return pci171x_ai_docmd_and_mode(3, dev
, s
);
1137 ==============================================================================
1138 Check if channel list from user is builded correctly
1139 If it's ok, then program scan/gain logic.
1140 This works for all cards.
1142 static int check_channel_list(struct comedi_device
*dev
,
1143 struct comedi_subdevice
*s
,
1144 unsigned int *chanlist
, unsigned int n_chan
)
1146 unsigned int chansegment
[32];
1147 unsigned int i
, nowmustbechan
, seglen
, segpos
;
1149 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan
);
1150 /* correct channel and range number check itself comedi/range.c */
1152 comedi_error(dev
, "range/channel list is empty!");
1157 chansegment
[0] = chanlist
[0]; /* first channel is everytime ok */
1158 for (i
= 1, seglen
= 1; i
< n_chan
; i
++, seglen
++) { /* build part of chanlist */
1159 /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1160 if (chanlist
[0] == chanlist
[i
])
1161 break; /* we detect loop, this must by finish */
1162 if (CR_CHAN(chanlist
[i
]) & 1) /* odd channel cann't by differencial */
1163 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
) {
1165 "Odd channel can't be differential input!\n");
1169 (CR_CHAN(chansegment
[i
- 1]) + 1) % s
->n_chan
;
1170 if (CR_AREF(chansegment
[i
- 1]) == AREF_DIFF
)
1171 nowmustbechan
= (nowmustbechan
+ 1) % s
->n_chan
;
1172 if (nowmustbechan
!= CR_CHAN(chanlist
[i
])) { /* channel list isn't continous :-( */
1174 ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1175 i
, CR_CHAN(chanlist
[i
]), nowmustbechan
,
1176 CR_CHAN(chanlist
[0]));
1179 chansegment
[i
] = chanlist
[i
]; /* well, this is next correct channel in list */
1182 for (i
= 0, segpos
= 0; i
< n_chan
; i
++) { /* check whole chanlist */
1183 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1184 if (chanlist
[i
] != chansegment
[i
% seglen
]) {
1186 ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1187 i
, CR_CHAN(chansegment
[i
]),
1188 CR_RANGE(chansegment
[i
]),
1189 CR_AREF(chansegment
[i
]),
1190 CR_CHAN(chanlist
[i
% seglen
]),
1191 CR_RANGE(chanlist
[i
% seglen
]),
1192 CR_AREF(chansegment
[i
% seglen
]));
1193 return 0; /* chan/gain list is strange */
1202 static void setup_channel_list(struct comedi_device
*dev
,
1203 struct comedi_subdevice
*s
,
1204 unsigned int *chanlist
, unsigned int n_chan
,
1205 unsigned int seglen
)
1207 unsigned int i
, range
, chanprog
;
1209 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan
,
1211 devpriv
->act_chanlist_len
= seglen
;
1212 devpriv
->act_chanlist_pos
= 0;
1214 DPRINTK("SegLen: %d\n", seglen
);
1215 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
1216 chanprog
= muxonechan
[CR_CHAN(chanlist
[i
])];
1217 outw(chanprog
, dev
->iobase
+ PCI171x_MUX
); /* select channel */
1218 range
= this_board
->rangecode_ai
[CR_RANGE(chanlist
[i
])];
1219 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
)
1221 outw(range
, dev
->iobase
+ PCI171x_RANGE
); /* select gain */
1222 #ifdef PCI171x_PARANOIDCHECK
1223 devpriv
->act_chanlist
[i
] =
1224 (CR_CHAN(chanlist
[i
]) << 12) & 0xf000;
1226 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i
, chanprog
, range
,
1227 devpriv
->act_chanlist
[i
]);
1229 #ifdef PCI171x_PARANOIDCHECK
1230 for ( ; i
< n_chan
; i
++) { /* store remainder of channel list */
1231 devpriv
->act_chanlist
[i
] =
1232 (CR_CHAN(chanlist
[i
]) << 12) & 0xf000;
1236 devpriv
->ai_et_MuxVal
=
1237 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8);
1238 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
); /* select channel interval to scan */
1239 DPRINTK("MUX: %4x L%4x.H%4x\n",
1240 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8),
1241 CR_CHAN(chanlist
[0]), CR_CHAN(chanlist
[seglen
- 1]));
1245 ==============================================================================
1247 static void start_pacer(struct comedi_device
*dev
, int mode
,
1248 unsigned int divisor1
, unsigned int divisor2
)
1250 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode
,
1251 divisor1
, divisor2
);
1252 outw(0xb4, dev
->iobase
+ PCI171x_CNTCTRL
);
1253 outw(0x74, dev
->iobase
+ PCI171x_CNTCTRL
);
1256 outw(divisor2
& 0xff, dev
->iobase
+ PCI171x_CNT2
);
1257 outw((divisor2
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT2
);
1258 outw(divisor1
& 0xff, dev
->iobase
+ PCI171x_CNT1
);
1259 outw((divisor1
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT1
);
1261 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1265 ==============================================================================
1267 static int pci171x_ai_cancel(struct comedi_device
*dev
,
1268 struct comedi_subdevice
*s
)
1270 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1272 switch (this_board
->cardtype
) {
1274 devpriv
->CntrlReg
&= Control_CNT0
;
1275 devpriv
->CntrlReg
|= Control_SW
;
1277 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1278 start_pacer(dev
, -1, 0, 0);
1279 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
1280 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
1285 devpriv
->ai_act_scan
= 0;
1286 s
->async
->cur_chan
= 0;
1287 devpriv
->ai_buf_ptr
= 0;
1288 devpriv
->neverending_ai
= 0;
1290 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1295 ==============================================================================
1297 static int pci171x_reset(struct comedi_device
*dev
)
1299 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1300 outw(0x30, dev
->iobase
+ PCI171x_CNTCTRL
);
1301 devpriv
->CntrlReg
= Control_SW
| Control_CNT0
; /* Software trigger, CNT0=external */
1302 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1303 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1304 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1305 start_pacer(dev
, -1, 0, 0); /* stop 8254 */
1306 devpriv
->da_ranges
= 0;
1307 if (this_board
->n_aochan
) {
1308 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
); /* set DACs to 0..5V */
1309 outw(0, dev
->iobase
+ PCI171x_DA1
); /* set DA outputs to 0V */
1310 devpriv
->ao_data
[0] = 0x0000;
1311 if (this_board
->n_aochan
> 1) {
1312 outw(0, dev
->iobase
+ PCI171x_DA2
);
1313 devpriv
->ao_data
[1] = 0x0000;
1316 outw(0, dev
->iobase
+ PCI171x_DO
); /* digital outputs to 0 */
1317 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1318 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1320 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1325 ==============================================================================
1327 static int pci1720_reset(struct comedi_device
*dev
)
1329 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1330 outb(Syncont_SC0
, dev
->iobase
+ PCI1720_SYNCONT
); /* set synchronous output mode */
1331 devpriv
->da_ranges
= 0xAA;
1332 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI1720_RANGE
); /* set all ranges to +/-5V */
1333 outw(0x0800, dev
->iobase
+ PCI1720_DA0
); /* set outputs to 0V */
1334 outw(0x0800, dev
->iobase
+ PCI1720_DA1
);
1335 outw(0x0800, dev
->iobase
+ PCI1720_DA2
);
1336 outw(0x0800, dev
->iobase
+ PCI1720_DA3
);
1337 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
1338 devpriv
->ao_data
[0] = 0x0800;
1339 devpriv
->ao_data
[1] = 0x0800;
1340 devpriv
->ao_data
[2] = 0x0800;
1341 devpriv
->ao_data
[3] = 0x0800;
1342 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1347 ==============================================================================
1349 static int pci1710_reset(struct comedi_device
*dev
)
1351 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1352 switch (this_board
->cardtype
) {
1354 return pci1720_reset(dev
);
1356 return pci171x_reset(dev
);
1358 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1362 ==============================================================================
1364 static int pci1710_attach(struct comedi_device
*dev
,
1365 struct comedi_devconfig
*it
)
1367 struct comedi_subdevice
*s
;
1368 int ret
, subdev
, n_subdevices
;
1370 unsigned long iobase
;
1371 struct pci_dev
*pcidev
;
1372 int opt_bus
, opt_slot
;
1374 unsigned char pci_bus
, pci_slot
, pci_func
;
1378 printk("comedi%d: adv_pci1710: ", dev
->minor
);
1380 opt_bus
= it
->options
[0];
1381 opt_slot
= it
->options
[1];
1383 ret
= alloc_private(dev
, sizeof(struct pci1710_private
));
1385 printk(" - Allocation failed!\n");
1389 /* Look for matching PCI device */
1390 errstr
= "not found!";
1392 board_index
= this_board
- boardtypes
;
1393 while (NULL
!= (pcidev
= pci_get_device(PCI_VENDOR_ID_ADVANTECH
,
1394 PCI_ANY_ID
, pcidev
))) {
1395 if (strcmp(this_board
->name
, DRV_NAME
) == 0) {
1396 for (i
= 0; i
< n_boardtypes
; ++i
) {
1397 if (pcidev
->device
== boardtypes
[i
].device_id
) {
1402 if (i
== n_boardtypes
)
1405 if (pcidev
->device
!= boardtypes
[board_index
].device_id
)
1409 /* Found matching vendor/device. */
1410 if (opt_bus
|| opt_slot
) {
1411 /* Check bus/slot. */
1412 if (opt_bus
!= pcidev
->bus
->number
1413 || opt_slot
!= PCI_SLOT(pcidev
->devfn
))
1414 continue; /* no match */
1417 * Look for device that isn't in use.
1418 * Enable PCI device and request regions.
1420 if (comedi_pci_enable(pcidev
, DRV_NAME
)) {
1422 "failed to enable PCI device and request regions!";
1425 /* fixup board_ptr in case we were using the dummy entry with the driver name */
1426 dev
->board_ptr
= &boardtypes
[board_index
];
1431 if (opt_bus
|| opt_slot
) {
1432 printk(" - Card at b:s %d:%d %s\n",
1433 opt_bus
, opt_slot
, errstr
);
1435 printk(" - Card %s\n", errstr
);
1440 pci_bus
= pcidev
->bus
->number
;
1441 pci_slot
= PCI_SLOT(pcidev
->devfn
);
1442 pci_func
= PCI_FUNC(pcidev
->devfn
);
1444 iobase
= pci_resource_start(pcidev
, 2);
1446 printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus
, pci_slot
, pci_func
,
1449 dev
->iobase
= iobase
;
1451 dev
->board_name
= this_board
->name
;
1452 devpriv
->pcidev
= pcidev
;
1455 if (this_board
->n_aichan
)
1457 if (this_board
->n_aochan
)
1459 if (this_board
->n_dichan
)
1461 if (this_board
->n_dochan
)
1463 if (this_board
->n_counter
)
1466 ret
= alloc_subdevices(dev
, n_subdevices
);
1468 printk(" - Allocation failed!\n");
1474 if (this_board
->have_irq
) {
1476 if (request_irq(irq
, interrupt_service_pci1710
,
1477 IRQF_SHARED
, "Advantech PCI-1710",
1480 (", unable to allocate IRQ %d, DISABLING IT",
1482 irq
= 0; /* Can't use IRQ */
1484 printk(", irq=%u", irq
);
1487 printk(", IRQ disabled");
1499 if (this_board
->n_aichan
) {
1500 s
= dev
->subdevices
+ subdev
;
1501 dev
->read_subdev
= s
;
1502 s
->type
= COMEDI_SUBD_AI
;
1503 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
1504 if (this_board
->n_aichand
)
1505 s
->subdev_flags
|= SDF_DIFF
;
1506 s
->n_chan
= this_board
->n_aichan
;
1507 s
->maxdata
= this_board
->ai_maxdata
;
1508 s
->len_chanlist
= this_board
->n_aichan
;
1509 s
->range_table
= this_board
->rangelist_ai
;
1510 s
->cancel
= pci171x_ai_cancel
;
1511 s
->insn_read
= pci171x_insn_read_ai
;
1513 s
->subdev_flags
|= SDF_CMD_READ
;
1514 s
->do_cmdtest
= pci171x_ai_cmdtest
;
1515 s
->do_cmd
= pci171x_ai_cmd
;
1517 devpriv
->i8254_osc_base
= 100; /* 100ns=10MHz */
1521 if (this_board
->n_aochan
) {
1522 s
= dev
->subdevices
+ subdev
;
1523 s
->type
= COMEDI_SUBD_AO
;
1524 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1525 s
->n_chan
= this_board
->n_aochan
;
1526 s
->maxdata
= this_board
->ao_maxdata
;
1527 s
->len_chanlist
= this_board
->n_aochan
;
1528 s
->range_table
= this_board
->rangelist_ao
;
1529 switch (this_board
->cardtype
) {
1531 s
->insn_write
= pci1720_insn_write_ao
;
1534 s
->insn_write
= pci171x_insn_write_ao
;
1537 s
->insn_read
= pci171x_insn_read_ao
;
1541 if (this_board
->n_dichan
) {
1542 s
= dev
->subdevices
+ subdev
;
1543 s
->type
= COMEDI_SUBD_DI
;
1544 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_COMMON
;
1545 s
->n_chan
= this_board
->n_dichan
;
1547 s
->len_chanlist
= this_board
->n_dichan
;
1548 s
->range_table
= &range_digital
;
1549 s
->io_bits
= 0; /* all bits input */
1550 s
->insn_bits
= pci171x_insn_bits_di
;
1554 if (this_board
->n_dochan
) {
1555 s
= dev
->subdevices
+ subdev
;
1556 s
->type
= COMEDI_SUBD_DO
;
1557 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1558 s
->n_chan
= this_board
->n_dochan
;
1560 s
->len_chanlist
= this_board
->n_dochan
;
1561 s
->range_table
= &range_digital
;
1562 s
->io_bits
= (1 << this_board
->n_dochan
) - 1; /* all bits output */
1564 s
->insn_bits
= pci171x_insn_bits_do
;
1568 if (this_board
->n_counter
) {
1569 s
= dev
->subdevices
+ subdev
;
1570 s
->type
= COMEDI_SUBD_COUNTER
;
1571 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
1572 s
->n_chan
= this_board
->n_counter
;
1573 s
->len_chanlist
= this_board
->n_counter
;
1574 s
->maxdata
= 0xffff;
1575 s
->range_table
= &range_unknown
;
1576 s
->insn_read
= pci171x_insn_counter_read
;
1577 s
->insn_write
= pci171x_insn_counter_write
;
1578 s
->insn_config
= pci171x_insn_counter_config
;
1588 ==============================================================================
1590 static int pci1710_detach(struct comedi_device
*dev
)
1597 free_irq(dev
->irq
, dev
);
1598 if (devpriv
->pcidev
) {
1600 comedi_pci_disable(devpriv
->pcidev
);
1602 pci_dev_put(devpriv
->pcidev
);
1610 ==============================================================================
1612 COMEDI_PCI_INITCLEANUP(driver_pci1710
, pci1710_pci_table
);
1614 ==============================================================================
1617 MODULE_AUTHOR("Comedi http://www.comedi.org");
1618 MODULE_DESCRIPTION("Comedi low-level driver");
1619 MODULE_LICENSE("GPL");