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
54 * correct channel number on every 12 bit
57 #undef PCI171X_EXTDEBUG
59 #define DRV_NAME "adv_pci1710"
62 #ifdef PCI171X_EXTDEBUG
63 #define DPRINTK(fmt, args...) printk(fmt, ## args)
65 #define DPRINTK(fmt, args...)
68 #define PCI_VENDOR_ID_ADVANTECH 0x13fe
70 /* hardware types of the cards */
71 #define TYPE_PCI171X 0
72 #define TYPE_PCI1713 2
73 #define TYPE_PCI1720 3
75 #define IORANGE_171x 32
76 #define IORANGE_1720 16
78 #define PCI171x_AD_DATA 0 /* R: A/D data */
79 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
80 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
81 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
82 #define PCI171x_STATUS 6 /* R: status register */
83 #define PCI171x_CONTROL 6 /* W: control register */
84 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
85 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
86 #define PCI171x_DA1 10 /* W: D/A register */
87 #define PCI171x_DA2 12 /* W: D/A register */
88 #define PCI171x_DAREF 14 /* W: D/A reference control */
89 #define PCI171x_DI 16 /* R: digi inputs */
90 #define PCI171x_DO 16 /* R: digi inputs */
91 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
92 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
93 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
94 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
96 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
98 #define Status_FE 0x0100 /* 1=FIFO is empty */
99 #define Status_FH 0x0200 /* 1=FIFO is half full */
100 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
101 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
102 /* bits from control register (PCI171x_CONTROL) */
103 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
104 * 0=have internal 100kHz source */
105 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
106 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
107 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
108 #define Control_EXT 0x0004 /* 1=external trigger source */
109 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
110 #define Control_SW 0x0001 /* 1=enable software trigger source */
111 /* bits from counter control register (PCI171x_CNTCTRL) */
112 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
113 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
114 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
115 #define Counter_M2 0x0008
116 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
117 #define Counter_RW1 0x0020
118 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
119 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
120 * 11 for read-back command */
122 #define PCI1720_DA0 0 /* W: D/A register 0 */
123 #define PCI1720_DA1 2 /* W: D/A register 1 */
124 #define PCI1720_DA2 4 /* W: D/A register 2 */
125 #define PCI1720_DA3 6 /* W: D/A register 3 */
126 #define PCI1720_RANGE 8 /* R/W: D/A range register */
127 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
128 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
130 /* D/A synchronized control (PCI1720_SYNCONT) */
131 #define Syncont_SC0 1 /* set synchronous output mode */
133 static const struct comedi_lrange range_pci1710_3
= { 9, {
146 static const char range_codes_pci1710_3
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
147 0x10, 0x11, 0x12, 0x13 };
149 static const struct comedi_lrange range_pci1710hg
= { 12, {
165 static const char range_codes_pci1710hg
[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
166 0x05, 0x06, 0x07, 0x10, 0x11,
169 static const struct comedi_lrange range_pci17x1
= { 5, {
178 static const char range_codes_pci17x1
[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
180 static const struct comedi_lrange range_pci1720
= { 4, {
188 static const struct comedi_lrange range_pci171x_da
= { 2, {
194 static int pci1710_attach(struct comedi_device
*dev
,
195 struct comedi_devconfig
*it
);
196 static int pci1710_detach(struct comedi_device
*dev
);
199 const char *name
; /* board name */
201 int iorange
; /* I/O range len */
202 char have_irq
; /* 1=card support IRQ */
203 char cardtype
; /* 0=1710& co. 2=1713, ... */
204 int n_aichan
; /* num of A/D chans */
205 int n_aichand
; /* num of A/D chans in diff mode */
206 int n_aochan
; /* num of D/A chans */
207 int n_dichan
; /* num of DI chans */
208 int n_dochan
; /* num of DO chans */
209 int n_counter
; /* num of counters */
210 int ai_maxdata
; /* resolution of A/D */
211 int ao_maxdata
; /* resolution of D/A */
212 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
213 const char *rangecode_ai
; /* range codes for programming */
214 const struct comedi_lrange
*rangelist_ao
; /* rangelist for D/A */
215 unsigned int ai_ns_min
; /* max sample speed of card v ns */
216 unsigned int fifo_half_size
; /* size of FIFO/2 */
219 static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table
) = {
220 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH
, 0x1710) },
221 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH
, 0x1711) },
222 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH
, 0x1713) },
223 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH
, 0x1720) },
224 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH
, 0x1731) },
228 MODULE_DEVICE_TABLE(pci
, pci1710_pci_table
);
230 static const struct boardtype boardtypes
[] = {
232 IORANGE_171x
, 1, TYPE_PCI171X
,
233 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
234 &range_pci1710_3
, range_codes_pci1710_3
,
237 {"pci1710hg", 0x1710,
238 IORANGE_171x
, 1, TYPE_PCI171X
,
239 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
240 &range_pci1710hg
, range_codes_pci1710hg
,
244 IORANGE_171x
, 1, TYPE_PCI171X
,
245 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
246 &range_pci17x1
, range_codes_pci17x1
, &range_pci171x_da
,
249 IORANGE_171x
, 1, TYPE_PCI1713
,
250 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
251 &range_pci1710_3
, range_codes_pci1710_3
, NULL
,
254 IORANGE_1720
, 0, TYPE_PCI1720
,
255 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
256 NULL
, NULL
, &range_pci1720
,
259 IORANGE_171x
, 1, TYPE_PCI171X
,
260 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
261 &range_pci17x1
, range_codes_pci17x1
, NULL
,
263 /* dummy entry corresponding to driver name */
267 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
269 static struct comedi_driver driver_pci1710
= {
270 .driver_name
= DRV_NAME
,
271 .module
= THIS_MODULE
,
272 .attach
= pci1710_attach
,
273 .detach
= pci1710_detach
,
274 .num_names
= n_boardtypes
,
275 .board_name
= &boardtypes
[0].name
,
276 .offset
= sizeof(struct boardtype
),
279 struct pci1710_private
{
280 struct pci_dev
*pcidev
; /* ptr to PCI device */
281 char valid
; /* card is usable */
282 char neverending_ai
; /* we do unlimited AI */
283 unsigned int CntrlReg
; /* Control register */
284 unsigned int i8254_osc_base
; /* frequence of onboard oscilator */
285 unsigned int ai_do
; /* what do AI? 0=nothing, 1 to 4 mode */
286 unsigned int ai_act_scan
; /* how many scans we finished */
287 unsigned int ai_act_chan
; /* actual position in actual scan */
288 unsigned int ai_buf_ptr
; /* data buffer ptr in samples */
289 unsigned char ai_eos
; /* 1=EOS wake up */
291 unsigned int ai_et_CntrlReg
;
292 unsigned int ai_et_MuxVal
;
293 unsigned int ai_et_div1
, ai_et_div2
;
294 unsigned int act_chanlist
[32]; /* list of scaned channel */
295 unsigned char act_chanlist_len
; /* len of scanlist */
296 unsigned char act_chanlist_pos
; /* actual position in MUX list */
297 unsigned char da_ranges
; /* copy of D/A outpit range register */
298 unsigned int ai_scans
; /* len of scanlist */
299 unsigned int ai_n_chan
; /* how many channels is measured */
300 unsigned int *ai_chanlist
; /* actaul chanlist */
301 unsigned int ai_flags
; /* flaglist */
302 unsigned int ai_data_len
; /* len of data buffer */
303 short *ai_data
; /* data buffer */
304 unsigned int ai_timer1
; /* timers */
305 unsigned int ai_timer2
;
306 short ao_data
[4]; /* data output buffer */
307 unsigned int cnt0_write_wait
; /* after a write, wait for update of the
311 #define devpriv ((struct pci1710_private *)dev->private)
312 #define this_board ((const struct boardtype *)dev->board_ptr)
315 ==============================================================================
318 static int check_channel_list(struct comedi_device
*dev
,
319 struct comedi_subdevice
*s
,
320 unsigned int *chanlist
, unsigned int n_chan
);
321 static void setup_channel_list(struct comedi_device
*dev
,
322 struct comedi_subdevice
*s
,
323 unsigned int *chanlist
, unsigned int n_chan
,
324 unsigned int seglen
);
325 static void start_pacer(struct comedi_device
*dev
, int mode
,
326 unsigned int divisor1
, unsigned int divisor2
);
327 static int pci1710_reset(struct comedi_device
*dev
);
328 static int pci171x_ai_cancel(struct comedi_device
*dev
,
329 struct comedi_subdevice
*s
);
331 /* used for gain list programming */
332 static const unsigned int muxonechan
[] = {
333 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
334 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
335 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
336 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
340 ==============================================================================
342 static int pci171x_insn_read_ai(struct comedi_device
*dev
,
343 struct comedi_subdevice
*s
,
344 struct comedi_insn
*insn
, unsigned int *data
)
347 #ifdef PCI171x_PARANOIDCHECK
351 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
352 devpriv
->CntrlReg
&= Control_CNT0
;
353 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
354 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
355 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
356 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
358 setup_channel_list(dev
, s
, &insn
->chanspec
, 1, 1);
360 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
361 inw(dev
->iobase
+ PCI171x_STATUS
),
362 dev
->iobase
+ PCI171x_STATUS
);
363 for (n
= 0; n
< insn
->n
; n
++) {
364 outw(0, dev
->iobase
+ PCI171x_SOFTTRG
); /* start conversion */
365 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n
,
366 inw(dev
->iobase
+ PCI171x_STATUS
));
368 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n
,
369 inw(dev
->iobase
+ PCI171x_STATUS
));
372 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
))
375 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n
,
377 inw(dev
->iobase
+ PCI171x_STATUS
));
379 comedi_error(dev
, "A/D insn timeout");
380 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
381 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
384 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
389 #ifdef PCI171x_PARANOIDCHECK
390 idata
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
391 if (this_board
->cardtype
!= TYPE_PCI1713
)
392 if ((idata
& 0xf000) != devpriv
->act_chanlist
[0]) {
393 comedi_error(dev
, "A/D insn data droput!");
396 data
[n
] = idata
& 0x0fff;
398 data
[n
] = inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff;
403 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
404 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
406 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n
);
411 ==============================================================================
413 static int pci171x_insn_write_ao(struct comedi_device
*dev
,
414 struct comedi_subdevice
*s
,
415 struct comedi_insn
*insn
, unsigned int *data
)
417 int n
, chan
, range
, ofs
;
419 chan
= CR_CHAN(insn
->chanspec
);
420 range
= CR_RANGE(insn
->chanspec
);
422 devpriv
->da_ranges
&= 0xfb;
423 devpriv
->da_ranges
|= (range
<< 2);
424 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
427 devpriv
->da_ranges
&= 0xfe;
428 devpriv
->da_ranges
|= range
;
429 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
433 for (n
= 0; n
< insn
->n
; n
++)
434 outw(data
[n
], dev
->iobase
+ ofs
);
436 devpriv
->ao_data
[chan
] = data
[n
];
443 ==============================================================================
445 static int pci171x_insn_read_ao(struct comedi_device
*dev
,
446 struct comedi_subdevice
*s
,
447 struct comedi_insn
*insn
, unsigned int *data
)
451 chan
= CR_CHAN(insn
->chanspec
);
452 for (n
= 0; n
< insn
->n
; n
++)
453 data
[n
] = devpriv
->ao_data
[chan
];
459 ==============================================================================
461 static int pci171x_insn_bits_di(struct comedi_device
*dev
,
462 struct comedi_subdevice
*s
,
463 struct comedi_insn
*insn
, unsigned int *data
)
465 data
[1] = inw(dev
->iobase
+ PCI171x_DI
);
471 ==============================================================================
473 static int pci171x_insn_bits_do(struct comedi_device
*dev
,
474 struct comedi_subdevice
*s
,
475 struct comedi_insn
*insn
, unsigned int *data
)
478 s
->state
&= ~data
[0];
479 s
->state
|= (data
[0] & data
[1]);
480 outw(s
->state
, dev
->iobase
+ PCI171x_DO
);
488 ==============================================================================
490 static int pci171x_insn_counter_read(struct comedi_device
*dev
,
491 struct comedi_subdevice
*s
,
492 struct comedi_insn
*insn
,
495 unsigned int msb
, lsb
, ccntrl
;
498 ccntrl
= 0xD2; /* count only */
499 for (i
= 0; i
< insn
->n
; i
++) {
500 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
502 lsb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
503 msb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
505 data
[0] = lsb
| (msb
<< 8);
512 ==============================================================================
514 static int pci171x_insn_counter_write(struct comedi_device
*dev
,
515 struct comedi_subdevice
*s
,
516 struct comedi_insn
*insn
,
519 uint msb
, lsb
, ccntrl
, status
;
521 lsb
= data
[0] & 0x00FF;
522 msb
= (data
[0] & 0xFF00) >> 8;
524 /* write lsb, then msb */
525 outw(lsb
, dev
->iobase
+ PCI171x_CNT0
);
526 outw(msb
, dev
->iobase
+ PCI171x_CNT0
);
528 if (devpriv
->cnt0_write_wait
) {
529 /* wait for the new count to be loaded */
532 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
533 status
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
534 } while (status
& 0x40);
541 ==============================================================================
543 static int pci171x_insn_counter_config(struct comedi_device
*dev
,
544 struct comedi_subdevice
*s
,
545 struct comedi_insn
*insn
,
549 /* This doesn't work like a normal Comedi counter config */
552 devpriv
->cnt0_write_wait
= data
[0] & 0x20;
554 /* internal or external clock? */
555 if (!(data
[0] & 0x10)) { /* internal */
556 devpriv
->CntrlReg
&= ~Control_CNT0
;
558 devpriv
->CntrlReg
|= Control_CNT0
;
560 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
563 ccntrl
|= Counter_M0
;
565 ccntrl
|= Counter_M1
;
567 ccntrl
|= Counter_M2
;
569 ccntrl
|= Counter_BCD
;
570 ccntrl
|= Counter_RW0
; /* set read/write mode */
571 ccntrl
|= Counter_RW1
;
572 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
579 ==============================================================================
581 static int pci1720_insn_write_ao(struct comedi_device
*dev
,
582 struct comedi_subdevice
*s
,
583 struct comedi_insn
*insn
, unsigned int *data
)
585 int n
, rangereg
, chan
;
587 chan
= CR_CHAN(insn
->chanspec
);
588 rangereg
= devpriv
->da_ranges
& (~(0x03 << (chan
<< 1)));
589 rangereg
|= (CR_RANGE(insn
->chanspec
) << (chan
<< 1));
590 if (rangereg
!= devpriv
->da_ranges
) {
591 outb(rangereg
, dev
->iobase
+ PCI1720_RANGE
);
592 devpriv
->da_ranges
= rangereg
;
595 for (n
= 0; n
< insn
->n
; n
++) {
596 outw(data
[n
], dev
->iobase
+ PCI1720_DA0
+ (chan
<< 1));
597 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
600 devpriv
->ao_data
[chan
] = data
[n
];
606 ==============================================================================
608 static void interrupt_pci1710_every_sample(void *d
)
610 struct comedi_device
*dev
= d
;
611 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
613 #ifdef PCI171x_PARANOIDCHECK
617 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
618 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
620 printk("comedi%d: A/D FIFO empty (%4x)\n", dev
->minor
, m
);
621 pci171x_ai_cancel(dev
, s
);
622 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
623 comedi_event(dev
, s
);
628 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
630 pci171x_ai_cancel(dev
, s
);
631 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
632 comedi_event(dev
, s
);
636 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
639 for (; !(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
);) {
640 #ifdef PCI171x_PARANOIDCHECK
641 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
642 DPRINTK("%04x:", sampl
);
643 if (this_board
->cardtype
!= TYPE_PCI1713
)
644 if ((sampl
& 0xf000) !=
645 devpriv
->act_chanlist
[s
->async
->cur_chan
]) {
647 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
648 (sampl
& 0xf000) >> 12,
651 async
->cur_chan
] & 0xf000) >>
653 pci171x_ai_cancel(dev
, s
);
655 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
656 comedi_event(dev
, s
);
659 DPRINTK("%8d %2d %8d~", s
->async
->buf_int_ptr
,
660 s
->async
->cur_chan
, s
->async
->buf_int_count
);
661 comedi_buf_put(s
->async
, sampl
& 0x0fff);
663 comedi_buf_put(s
->async
,
664 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
666 ++s
->async
->cur_chan
;
668 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
)
669 s
->async
->cur_chan
= 0;
672 if (s
->async
->cur_chan
== 0) { /* one scan done */
673 devpriv
->ai_act_scan
++;
675 ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
676 s
->async
->buf_int_count
, s
->async
->buf_int_ptr
,
677 s
->async
->buf_user_count
, s
->async
->buf_user_ptr
);
678 DPRINTK("adv_pci1710 EDBG: EOS2\n");
679 if ((!devpriv
->neverending_ai
) && (devpriv
->ai_act_scan
>= devpriv
->ai_scans
)) { /* all data sampled */
680 pci171x_ai_cancel(dev
, s
);
681 s
->async
->events
|= COMEDI_CB_EOA
;
682 comedi_event(dev
, s
);
688 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
689 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
691 comedi_event(dev
, s
);
695 ==============================================================================
697 static int move_block_from_fifo(struct comedi_device
*dev
,
698 struct comedi_subdevice
*s
, int n
, int turn
)
701 #ifdef PCI171x_PARANOIDCHECK
704 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n
,
706 j
= s
->async
->cur_chan
;
707 for (i
= 0; i
< n
; i
++) {
708 #ifdef PCI171x_PARANOIDCHECK
709 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
710 if (this_board
->cardtype
!= TYPE_PCI1713
)
711 if ((sampl
& 0xf000) != devpriv
->act_chanlist
[j
]) {
713 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
714 dev
->minor
, (sampl
& 0xf000) >> 12,
715 (devpriv
->act_chanlist
[j
] & 0xf000) >> 12,
716 i
, j
, devpriv
->ai_act_scan
, n
, turn
,
718 pci171x_ai_cancel(dev
, s
);
720 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
721 comedi_event(dev
, s
);
724 comedi_buf_put(s
->async
, sampl
& 0x0fff);
726 comedi_buf_put(s
->async
,
727 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
730 if (j
>= devpriv
->ai_n_chan
) {
732 devpriv
->ai_act_scan
++;
735 s
->async
->cur_chan
= j
;
736 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
741 ==============================================================================
743 static void interrupt_pci1710_half_fifo(void *d
)
745 struct comedi_device
*dev
= d
;
746 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
749 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
750 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
751 if (!(m
& Status_FH
)) {
752 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
754 pci171x_ai_cancel(dev
, s
);
755 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
756 comedi_event(dev
, s
);
761 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
763 pci171x_ai_cancel(dev
, s
);
764 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
765 comedi_event(dev
, s
);
769 samplesinbuf
= this_board
->fifo_half_size
;
770 if (samplesinbuf
* sizeof(short) >= devpriv
->ai_data_len
) {
771 m
= devpriv
->ai_data_len
/ sizeof(short);
772 if (move_block_from_fifo(dev
, s
, m
, 0))
778 if (move_block_from_fifo(dev
, s
, samplesinbuf
, 1))
782 if (!devpriv
->neverending_ai
)
783 if (devpriv
->ai_act_scan
>= devpriv
->ai_scans
) { /* all data
785 pci171x_ai_cancel(dev
, s
);
786 s
->async
->events
|= COMEDI_CB_EOA
;
787 comedi_event(dev
, s
);
790 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
791 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
793 comedi_event(dev
, s
);
797 ==============================================================================
799 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
801 struct comedi_device
*dev
= d
;
803 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
805 if (!dev
->attached
) /* is device attached? */
806 return IRQ_NONE
; /* no, exit */
808 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_IRQ
)) /* is this interrupt from our board? */
809 return IRQ_NONE
; /* no, exit */
811 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
812 inw(dev
->iobase
+ PCI171x_STATUS
));
814 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
816 devpriv
->CntrlReg
&= Control_CNT0
;
817 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
818 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
819 devpriv
->CntrlReg
= devpriv
->ai_et_CntrlReg
;
820 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
821 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
822 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
);
823 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
825 start_pacer(dev
, 1, devpriv
->ai_et_div1
, devpriv
->ai_et_div2
);
828 if (devpriv
->ai_eos
) { /* We use FIFO half full INT or not? */
829 interrupt_pci1710_every_sample(d
);
831 interrupt_pci1710_half_fifo(d
);
833 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
838 ==============================================================================
840 static int pci171x_ai_docmd_and_mode(int mode
, struct comedi_device
*dev
,
841 struct comedi_subdevice
*s
)
843 unsigned int divisor1
= 0, divisor2
= 0;
846 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
848 start_pacer(dev
, -1, 0, 0); /* stop pacer */
850 seglen
= check_channel_list(dev
, s
, devpriv
->ai_chanlist
,
854 setup_channel_list(dev
, s
, devpriv
->ai_chanlist
,
855 devpriv
->ai_n_chan
, seglen
);
857 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
858 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
860 devpriv
->ai_do
= mode
;
862 devpriv
->ai_act_scan
= 0;
863 s
->async
->cur_chan
= 0;
864 devpriv
->ai_buf_ptr
= 0;
865 devpriv
->neverending_ai
= 0;
867 devpriv
->CntrlReg
&= Control_CNT0
;
868 if ((devpriv
->ai_flags
& TRIG_WAKE_EOS
)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
871 devpriv
->CntrlReg
|= Control_ONEFH
;
875 if ((devpriv
->ai_scans
== 0) || (devpriv
->ai_scans
== -1))
876 devpriv
->neverending_ai
= 1;
877 /* well, user want neverending */
879 devpriv
->neverending_ai
= 0;
884 if (devpriv
->ai_timer1
< this_board
->ai_ns_min
)
885 devpriv
->ai_timer1
= this_board
->ai_ns_min
;
886 devpriv
->CntrlReg
|= Control_PACER
| Control_IRQEN
;
888 devpriv
->ai_et_CntrlReg
= devpriv
->CntrlReg
;
890 ~(Control_PACER
| Control_ONEFH
| Control_GATE
);
891 devpriv
->CntrlReg
|= Control_EXT
;
896 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
897 &divisor2
, &devpriv
->ai_timer1
,
898 devpriv
->ai_flags
& TRIG_ROUND_MASK
);
900 ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
901 devpriv
->i8254_osc_base
, divisor1
, divisor2
,
903 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
906 start_pacer(dev
, mode
, divisor1
, divisor2
);
908 devpriv
->ai_et_div1
= divisor1
;
909 devpriv
->ai_et_div2
= divisor2
;
913 devpriv
->CntrlReg
|= Control_EXT
| Control_IRQEN
;
914 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
918 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
922 #ifdef PCI171X_EXTDEBUG
924 ==============================================================================
926 static void pci171x_cmdtest_out(int e
, struct comedi_cmd
*cmd
)
928 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e
,
929 cmd
->start_src
, cmd
->scan_begin_src
, cmd
->convert_src
);
930 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e
,
931 cmd
->start_arg
, cmd
->scan_begin_arg
, cmd
->convert_arg
);
932 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e
, cmd
->stop_src
,
934 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
935 e
, cmd
->stop_arg
, cmd
->scan_end_arg
, cmd
->chanlist_len
);
940 ==============================================================================
942 static int pci171x_ai_cmdtest(struct comedi_device
*dev
,
943 struct comedi_subdevice
*s
,
944 struct comedi_cmd
*cmd
)
948 unsigned int divisor1
= 0, divisor2
= 0;
950 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
951 #ifdef PCI171X_EXTDEBUG
952 pci171x_cmdtest_out(-1, cmd
);
954 /* step 1: make sure trigger sources are trivially valid */
956 tmp
= cmd
->start_src
;
957 cmd
->start_src
&= TRIG_NOW
| TRIG_EXT
;
958 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
961 tmp
= cmd
->scan_begin_src
;
962 cmd
->scan_begin_src
&= TRIG_FOLLOW
;
963 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
966 tmp
= cmd
->convert_src
;
967 cmd
->convert_src
&= TRIG_TIMER
| TRIG_EXT
;
968 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
971 tmp
= cmd
->scan_end_src
;
972 cmd
->scan_end_src
&= TRIG_COUNT
;
973 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
977 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
978 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
982 #ifdef PCI171X_EXTDEBUG
983 pci171x_cmdtest_out(1, cmd
);
986 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
991 /* step 2: make sure trigger sources are unique and mutually compatible */
993 if (cmd
->start_src
!= TRIG_NOW
&& cmd
->start_src
!= TRIG_EXT
) {
994 cmd
->start_src
= TRIG_NOW
;
998 if (cmd
->scan_begin_src
!= TRIG_FOLLOW
) {
999 cmd
->scan_begin_src
= TRIG_FOLLOW
;
1003 if (cmd
->convert_src
!= TRIG_TIMER
&& cmd
->convert_src
!= TRIG_EXT
)
1006 if (cmd
->scan_end_src
!= TRIG_COUNT
) {
1007 cmd
->scan_end_src
= TRIG_COUNT
;
1011 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
1015 #ifdef PCI171X_EXTDEBUG
1016 pci171x_cmdtest_out(2, cmd
);
1019 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1024 /* step 3: make sure arguments are trivially compatible */
1026 if (cmd
->start_arg
!= 0) {
1031 if (cmd
->scan_begin_arg
!= 0) {
1032 cmd
->scan_begin_arg
= 0;
1036 if (cmd
->convert_src
== TRIG_TIMER
) {
1037 if (cmd
->convert_arg
< this_board
->ai_ns_min
) {
1038 cmd
->convert_arg
= this_board
->ai_ns_min
;
1041 } else { /* TRIG_FOLLOW */
1042 if (cmd
->convert_arg
!= 0) {
1043 cmd
->convert_arg
= 0;
1048 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1049 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1052 if (cmd
->stop_src
== TRIG_COUNT
) {
1053 if (!cmd
->stop_arg
) {
1057 } else { /* TRIG_NONE */
1058 if (cmd
->stop_arg
!= 0) {
1065 #ifdef PCI171X_EXTDEBUG
1066 pci171x_cmdtest_out(3, cmd
);
1069 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1074 /* step 4: fix up any arguments */
1076 if (cmd
->convert_src
== TRIG_TIMER
) {
1077 tmp
= cmd
->convert_arg
;
1078 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
1079 &divisor2
, &cmd
->convert_arg
,
1080 cmd
->flags
& TRIG_ROUND_MASK
);
1081 if (cmd
->convert_arg
< this_board
->ai_ns_min
)
1082 cmd
->convert_arg
= this_board
->ai_ns_min
;
1083 if (tmp
!= cmd
->convert_arg
)
1089 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1094 /* step 5: complain about special chanlist considerations */
1096 if (cmd
->chanlist
) {
1097 if (!check_channel_list(dev
, s
, cmd
->chanlist
,
1099 return 5; /* incorrect channels list */
1102 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1107 ==============================================================================
1109 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1111 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1113 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1114 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
1115 devpriv
->ai_chanlist
= cmd
->chanlist
;
1116 devpriv
->ai_flags
= cmd
->flags
;
1117 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
1118 devpriv
->ai_data
= s
->async
->prealloc_buf
;
1119 devpriv
->ai_timer1
= 0;
1120 devpriv
->ai_timer2
= 0;
1122 if (cmd
->stop_src
== TRIG_COUNT
)
1123 devpriv
->ai_scans
= cmd
->stop_arg
;
1125 devpriv
->ai_scans
= 0;
1128 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) { /* mode 1, 2, 3 */
1129 if (cmd
->convert_src
== TRIG_TIMER
) { /* mode 1 and 2 */
1130 devpriv
->ai_timer1
= cmd
->convert_arg
;
1131 return pci171x_ai_docmd_and_mode(cmd
->start_src
==
1132 TRIG_EXT
? 2 : 1, dev
,
1135 if (cmd
->convert_src
== TRIG_EXT
) { /* mode 3 */
1136 return pci171x_ai_docmd_and_mode(3, dev
, s
);
1144 ==============================================================================
1145 Check if channel list from user is builded correctly
1146 If it's ok, then program scan/gain logic.
1147 This works for all cards.
1149 static int check_channel_list(struct comedi_device
*dev
,
1150 struct comedi_subdevice
*s
,
1151 unsigned int *chanlist
, unsigned int n_chan
)
1153 unsigned int chansegment
[32];
1154 unsigned int i
, nowmustbechan
, seglen
, segpos
;
1156 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan
);
1157 /* correct channel and range number check itself comedi/range.c */
1159 comedi_error(dev
, "range/channel list is empty!");
1164 chansegment
[0] = chanlist
[0]; /* first channel is every time ok */
1165 for (i
= 1, seglen
= 1; i
< n_chan
; i
++, seglen
++) { /* build part of chanlist */
1166 /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1167 if (chanlist
[0] == chanlist
[i
])
1168 break; /* we detect loop, this must by finish */
1169 if (CR_CHAN(chanlist
[i
]) & 1) /* odd channel cann't by differencial */
1170 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
) {
1172 "Odd channel can't be differential input!\n");
1176 (CR_CHAN(chansegment
[i
- 1]) + 1) % s
->n_chan
;
1177 if (CR_AREF(chansegment
[i
- 1]) == AREF_DIFF
)
1178 nowmustbechan
= (nowmustbechan
+ 1) % s
->n_chan
;
1179 if (nowmustbechan
!= CR_CHAN(chanlist
[i
])) { /* channel list isn't continuous :-( */
1181 ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1182 i
, CR_CHAN(chanlist
[i
]), nowmustbechan
,
1183 CR_CHAN(chanlist
[0]));
1186 chansegment
[i
] = chanlist
[i
]; /* well, this is next correct channel in list */
1189 for (i
= 0, segpos
= 0; i
< n_chan
; i
++) { /* check whole chanlist */
1190 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1191 if (chanlist
[i
] != chansegment
[i
% seglen
]) {
1193 ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1194 i
, CR_CHAN(chansegment
[i
]),
1195 CR_RANGE(chansegment
[i
]),
1196 CR_AREF(chansegment
[i
]),
1197 CR_CHAN(chanlist
[i
% seglen
]),
1198 CR_RANGE(chanlist
[i
% seglen
]),
1199 CR_AREF(chansegment
[i
% seglen
]));
1200 return 0; /* chan/gain list is strange */
1209 static void setup_channel_list(struct comedi_device
*dev
,
1210 struct comedi_subdevice
*s
,
1211 unsigned int *chanlist
, unsigned int n_chan
,
1212 unsigned int seglen
)
1214 unsigned int i
, range
, chanprog
;
1216 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan
,
1218 devpriv
->act_chanlist_len
= seglen
;
1219 devpriv
->act_chanlist_pos
= 0;
1221 DPRINTK("SegLen: %d\n", seglen
);
1222 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
1223 chanprog
= muxonechan
[CR_CHAN(chanlist
[i
])];
1224 outw(chanprog
, dev
->iobase
+ PCI171x_MUX
); /* select channel */
1225 range
= this_board
->rangecode_ai
[CR_RANGE(chanlist
[i
])];
1226 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
)
1228 outw(range
, dev
->iobase
+ PCI171x_RANGE
); /* select gain */
1229 #ifdef PCI171x_PARANOIDCHECK
1230 devpriv
->act_chanlist
[i
] =
1231 (CR_CHAN(chanlist
[i
]) << 12) & 0xf000;
1233 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i
, chanprog
, range
,
1234 devpriv
->act_chanlist
[i
]);
1236 #ifdef PCI171x_PARANOIDCHECK
1237 for ( ; i
< n_chan
; i
++) { /* store remainder of channel list */
1238 devpriv
->act_chanlist
[i
] =
1239 (CR_CHAN(chanlist
[i
]) << 12) & 0xf000;
1243 devpriv
->ai_et_MuxVal
=
1244 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8);
1245 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
); /* select channel interval to scan */
1246 DPRINTK("MUX: %4x L%4x.H%4x\n",
1247 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8),
1248 CR_CHAN(chanlist
[0]), CR_CHAN(chanlist
[seglen
- 1]));
1252 ==============================================================================
1254 static void start_pacer(struct comedi_device
*dev
, int mode
,
1255 unsigned int divisor1
, unsigned int divisor2
)
1257 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode
,
1258 divisor1
, divisor2
);
1259 outw(0xb4, dev
->iobase
+ PCI171x_CNTCTRL
);
1260 outw(0x74, dev
->iobase
+ PCI171x_CNTCTRL
);
1263 outw(divisor2
& 0xff, dev
->iobase
+ PCI171x_CNT2
);
1264 outw((divisor2
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT2
);
1265 outw(divisor1
& 0xff, dev
->iobase
+ PCI171x_CNT1
);
1266 outw((divisor1
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT1
);
1268 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1272 ==============================================================================
1274 static int pci171x_ai_cancel(struct comedi_device
*dev
,
1275 struct comedi_subdevice
*s
)
1277 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1279 switch (this_board
->cardtype
) {
1281 devpriv
->CntrlReg
&= Control_CNT0
;
1282 devpriv
->CntrlReg
|= Control_SW
;
1284 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1285 start_pacer(dev
, -1, 0, 0);
1286 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
1287 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
1292 devpriv
->ai_act_scan
= 0;
1293 s
->async
->cur_chan
= 0;
1294 devpriv
->ai_buf_ptr
= 0;
1295 devpriv
->neverending_ai
= 0;
1297 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1302 ==============================================================================
1304 static int pci171x_reset(struct comedi_device
*dev
)
1306 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1307 outw(0x30, dev
->iobase
+ PCI171x_CNTCTRL
);
1308 devpriv
->CntrlReg
= Control_SW
| Control_CNT0
; /* Software trigger, CNT0=external */
1309 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1310 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1311 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1312 start_pacer(dev
, -1, 0, 0); /* stop 8254 */
1313 devpriv
->da_ranges
= 0;
1314 if (this_board
->n_aochan
) {
1315 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
); /* set DACs to 0..5V */
1316 outw(0, dev
->iobase
+ PCI171x_DA1
); /* set DA outputs to 0V */
1317 devpriv
->ao_data
[0] = 0x0000;
1318 if (this_board
->n_aochan
> 1) {
1319 outw(0, dev
->iobase
+ PCI171x_DA2
);
1320 devpriv
->ao_data
[1] = 0x0000;
1323 outw(0, dev
->iobase
+ PCI171x_DO
); /* digital outputs to 0 */
1324 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1325 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1327 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1332 ==============================================================================
1334 static int pci1720_reset(struct comedi_device
*dev
)
1336 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1337 outb(Syncont_SC0
, dev
->iobase
+ PCI1720_SYNCONT
); /* set synchronous output mode */
1338 devpriv
->da_ranges
= 0xAA;
1339 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI1720_RANGE
); /* set all ranges to +/-5V */
1340 outw(0x0800, dev
->iobase
+ PCI1720_DA0
); /* set outputs to 0V */
1341 outw(0x0800, dev
->iobase
+ PCI1720_DA1
);
1342 outw(0x0800, dev
->iobase
+ PCI1720_DA2
);
1343 outw(0x0800, dev
->iobase
+ PCI1720_DA3
);
1344 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
1345 devpriv
->ao_data
[0] = 0x0800;
1346 devpriv
->ao_data
[1] = 0x0800;
1347 devpriv
->ao_data
[2] = 0x0800;
1348 devpriv
->ao_data
[3] = 0x0800;
1349 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1354 ==============================================================================
1356 static int pci1710_reset(struct comedi_device
*dev
)
1358 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1359 switch (this_board
->cardtype
) {
1361 return pci1720_reset(dev
);
1363 return pci171x_reset(dev
);
1365 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1369 ==============================================================================
1371 static int pci1710_attach(struct comedi_device
*dev
,
1372 struct comedi_devconfig
*it
)
1374 struct comedi_subdevice
*s
;
1375 int ret
, subdev
, n_subdevices
;
1377 unsigned long iobase
;
1378 struct pci_dev
*pcidev
;
1379 int opt_bus
, opt_slot
;
1381 unsigned char pci_bus
, pci_slot
, pci_func
;
1385 printk("comedi%d: adv_pci1710: ", dev
->minor
);
1387 opt_bus
= it
->options
[0];
1388 opt_slot
= it
->options
[1];
1390 ret
= alloc_private(dev
, sizeof(struct pci1710_private
));
1392 printk(" - Allocation failed!\n");
1396 /* Look for matching PCI device */
1397 errstr
= "not found!";
1399 board_index
= this_board
- boardtypes
;
1400 while (NULL
!= (pcidev
= pci_get_device(PCI_VENDOR_ID_ADVANTECH
,
1401 PCI_ANY_ID
, pcidev
))) {
1402 if (strcmp(this_board
->name
, DRV_NAME
) == 0) {
1403 for (i
= 0; i
< n_boardtypes
; ++i
) {
1404 if (pcidev
->device
== boardtypes
[i
].device_id
) {
1409 if (i
== n_boardtypes
)
1412 if (pcidev
->device
!= boardtypes
[board_index
].device_id
)
1416 /* Found matching vendor/device. */
1417 if (opt_bus
|| opt_slot
) {
1418 /* Check bus/slot. */
1419 if (opt_bus
!= pcidev
->bus
->number
1420 || opt_slot
!= PCI_SLOT(pcidev
->devfn
))
1421 continue; /* no match */
1424 * Look for device that isn't in use.
1425 * Enable PCI device and request regions.
1427 if (comedi_pci_enable(pcidev
, DRV_NAME
)) {
1429 "failed to enable PCI device and request regions!";
1432 /* fixup board_ptr in case we were using the dummy entry with the driver name */
1433 dev
->board_ptr
= &boardtypes
[board_index
];
1438 if (opt_bus
|| opt_slot
) {
1439 printk(" - Card at b:s %d:%d %s\n",
1440 opt_bus
, opt_slot
, errstr
);
1442 printk(" - Card %s\n", errstr
);
1447 pci_bus
= pcidev
->bus
->number
;
1448 pci_slot
= PCI_SLOT(pcidev
->devfn
);
1449 pci_func
= PCI_FUNC(pcidev
->devfn
);
1451 iobase
= pci_resource_start(pcidev
, 2);
1453 printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus
, pci_slot
, pci_func
,
1456 dev
->iobase
= iobase
;
1458 dev
->board_name
= this_board
->name
;
1459 devpriv
->pcidev
= pcidev
;
1462 if (this_board
->n_aichan
)
1464 if (this_board
->n_aochan
)
1466 if (this_board
->n_dichan
)
1468 if (this_board
->n_dochan
)
1470 if (this_board
->n_counter
)
1473 ret
= alloc_subdevices(dev
, n_subdevices
);
1475 printk(" - Allocation failed!\n");
1481 if (this_board
->have_irq
) {
1483 if (request_irq(irq
, interrupt_service_pci1710
,
1484 IRQF_SHARED
, "Advantech PCI-1710",
1487 (", unable to allocate IRQ %d, DISABLING IT",
1489 irq
= 0; /* Can't use IRQ */
1491 printk(", irq=%u", irq
);
1494 printk(", IRQ disabled");
1506 if (this_board
->n_aichan
) {
1507 s
= dev
->subdevices
+ subdev
;
1508 dev
->read_subdev
= s
;
1509 s
->type
= COMEDI_SUBD_AI
;
1510 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
1511 if (this_board
->n_aichand
)
1512 s
->subdev_flags
|= SDF_DIFF
;
1513 s
->n_chan
= this_board
->n_aichan
;
1514 s
->maxdata
= this_board
->ai_maxdata
;
1515 s
->len_chanlist
= this_board
->n_aichan
;
1516 s
->range_table
= this_board
->rangelist_ai
;
1517 s
->cancel
= pci171x_ai_cancel
;
1518 s
->insn_read
= pci171x_insn_read_ai
;
1520 s
->subdev_flags
|= SDF_CMD_READ
;
1521 s
->do_cmdtest
= pci171x_ai_cmdtest
;
1522 s
->do_cmd
= pci171x_ai_cmd
;
1524 devpriv
->i8254_osc_base
= 100; /* 100ns=10MHz */
1528 if (this_board
->n_aochan
) {
1529 s
= dev
->subdevices
+ subdev
;
1530 s
->type
= COMEDI_SUBD_AO
;
1531 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1532 s
->n_chan
= this_board
->n_aochan
;
1533 s
->maxdata
= this_board
->ao_maxdata
;
1534 s
->len_chanlist
= this_board
->n_aochan
;
1535 s
->range_table
= this_board
->rangelist_ao
;
1536 switch (this_board
->cardtype
) {
1538 s
->insn_write
= pci1720_insn_write_ao
;
1541 s
->insn_write
= pci171x_insn_write_ao
;
1544 s
->insn_read
= pci171x_insn_read_ao
;
1548 if (this_board
->n_dichan
) {
1549 s
= dev
->subdevices
+ subdev
;
1550 s
->type
= COMEDI_SUBD_DI
;
1551 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_COMMON
;
1552 s
->n_chan
= this_board
->n_dichan
;
1554 s
->len_chanlist
= this_board
->n_dichan
;
1555 s
->range_table
= &range_digital
;
1556 s
->io_bits
= 0; /* all bits input */
1557 s
->insn_bits
= pci171x_insn_bits_di
;
1561 if (this_board
->n_dochan
) {
1562 s
= dev
->subdevices
+ subdev
;
1563 s
->type
= COMEDI_SUBD_DO
;
1564 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1565 s
->n_chan
= this_board
->n_dochan
;
1567 s
->len_chanlist
= this_board
->n_dochan
;
1568 s
->range_table
= &range_digital
;
1569 /* all bits output */
1570 s
->io_bits
= (1 << this_board
->n_dochan
) - 1;
1572 s
->insn_bits
= pci171x_insn_bits_do
;
1576 if (this_board
->n_counter
) {
1577 s
= dev
->subdevices
+ subdev
;
1578 s
->type
= COMEDI_SUBD_COUNTER
;
1579 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
1580 s
->n_chan
= this_board
->n_counter
;
1581 s
->len_chanlist
= this_board
->n_counter
;
1582 s
->maxdata
= 0xffff;
1583 s
->range_table
= &range_unknown
;
1584 s
->insn_read
= pci171x_insn_counter_read
;
1585 s
->insn_write
= pci171x_insn_counter_write
;
1586 s
->insn_config
= pci171x_insn_counter_config
;
1596 ==============================================================================
1598 static int pci1710_detach(struct comedi_device
*dev
)
1605 free_irq(dev
->irq
, dev
);
1606 if (devpriv
->pcidev
) {
1608 comedi_pci_disable(devpriv
->pcidev
);
1610 pci_dev_put(devpriv
->pcidev
);
1618 ==============================================================================
1620 static int __devinit
driver_pci1710_pci_probe(struct pci_dev
*dev
,
1621 const struct pci_device_id
*ent
)
1623 return comedi_pci_auto_config(dev
, driver_pci1710
.driver_name
);
1626 static void __devexit
driver_pci1710_pci_remove(struct pci_dev
*dev
)
1628 comedi_pci_auto_unconfig(dev
);
1631 static struct pci_driver driver_pci1710_pci_driver
= {
1632 .id_table
= pci1710_pci_table
,
1633 .probe
= &driver_pci1710_pci_probe
,
1634 .remove
= __devexit_p(&driver_pci1710_pci_remove
)
1637 static int __init
driver_pci1710_init_module(void)
1641 retval
= comedi_driver_register(&driver_pci1710
);
1645 driver_pci1710_pci_driver
.name
= (char *)driver_pci1710
.driver_name
;
1646 return pci_register_driver(&driver_pci1710_pci_driver
);
1649 static void __exit
driver_pci1710_cleanup_module(void)
1651 pci_unregister_driver(&driver_pci1710_pci_driver
);
1652 comedi_driver_unregister(&driver_pci1710
);
1655 module_init(driver_pci1710_init_module
);
1656 module_exit(driver_pci1710_cleanup_module
);
1658 ==============================================================================
1661 MODULE_AUTHOR("Comedi http://www.comedi.org");
1662 MODULE_DESCRIPTION("Comedi low-level driver");
1663 MODULE_LICENSE("GPL");