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...) rt_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 couter 0 */
88 #define PCI171x_CNT1 26 /* R/W: 8254 couter 1 */
89 #define PCI171x_CNT2 28 /* R/W: 8254 couter 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,
162 static const struct comedi_lrange range_pci17x1
= { 5, {
171 static const char range_codes_pci17x1
[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
173 static const struct comedi_lrange range_pci1720
= { 4, {
181 static const struct comedi_lrange range_pci171x_da
= { 2, {
187 static int pci1710_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
);
188 static int pci1710_detach(struct comedi_device
*dev
);
191 const char *name
; /* board name */
193 int iorange
; /* I/O range len */
194 char have_irq
; /* 1=card support IRQ */
195 char cardtype
; /* 0=1710& co. 2=1713, ... */
196 int n_aichan
; /* num of A/D chans */
197 int n_aichand
; /* num of A/D chans in diff mode */
198 int n_aochan
; /* num of D/A chans */
199 int n_dichan
; /* num of DI chans */
200 int n_dochan
; /* num of DO chans */
201 int n_counter
; /* num of counters */
202 int ai_maxdata
; /* resolution of A/D */
203 int ao_maxdata
; /* resolution of D/A */
204 const struct comedi_lrange
*rangelist_ai
; /* rangelist for A/D */
205 const char *rangecode_ai
; /* range codes for programming */
206 const struct comedi_lrange
*rangelist_ao
; /* rangelist for D/A */
207 unsigned int ai_ns_min
; /* max sample speed of card v ns */
208 unsigned int fifo_half_size
; /* size of FIFO/2 */
211 static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table
) = {
212 {PCI_VENDOR_ID_ADVANTECH
, 0x1710, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
213 {PCI_VENDOR_ID_ADVANTECH
, 0x1711, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
214 {PCI_VENDOR_ID_ADVANTECH
, 0x1713, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
215 {PCI_VENDOR_ID_ADVANTECH
, 0x1720, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
216 {PCI_VENDOR_ID_ADVANTECH
, 0x1731, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
220 MODULE_DEVICE_TABLE(pci
, pci1710_pci_table
);
222 static const struct boardtype boardtypes
[] = {
224 IORANGE_171x
, 1, TYPE_PCI171X
,
225 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
226 &range_pci1710_3
, range_codes_pci1710_3
,
229 {"pci1710hg", 0x1710,
230 IORANGE_171x
, 1, TYPE_PCI171X
,
231 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
232 &range_pci1710hg
, range_codes_pci1710hg
,
236 IORANGE_171x
, 1, TYPE_PCI171X
,
237 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
238 &range_pci17x1
, range_codes_pci17x1
, &range_pci171x_da
,
241 IORANGE_171x
, 1, TYPE_PCI1713
,
242 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
243 &range_pci1710_3
, range_codes_pci1710_3
, NULL
,
246 IORANGE_1720
, 0, TYPE_PCI1720
,
247 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
248 NULL
, NULL
, &range_pci1720
,
251 IORANGE_171x
, 1, TYPE_PCI171X
,
252 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
253 &range_pci17x1
, range_codes_pci17x1
, NULL
,
255 /* dummy entry corresponding to driver name */
259 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
261 static struct comedi_driver driver_pci1710
= {
262 .driver_name
= DRV_NAME
,
263 .module
= THIS_MODULE
,
264 .attach
= pci1710_attach
,
265 .detach
= pci1710_detach
,
266 .num_names
= n_boardtypes
,
267 .board_name
= &boardtypes
[0].name
,
268 .offset
= sizeof(struct boardtype
),
271 struct pci1710_private
{
272 struct pci_dev
*pcidev
; /* ptr to PCI device */
273 char valid
; /* card is usable */
274 char neverending_ai
; /* we do unlimited AI */
275 unsigned int CntrlReg
; /* Control register */
276 unsigned int i8254_osc_base
; /* frequence of onboard oscilator */
277 unsigned int ai_do
; /* what do AI? 0=nothing, 1 to 4 mode */
278 unsigned int ai_act_scan
; /* how many scans we finished */
279 unsigned int ai_act_chan
; /* actual position in actual scan */
280 unsigned int ai_buf_ptr
; /* data buffer ptr in samples */
281 unsigned char ai_eos
; /* 1=EOS wake up */
283 unsigned int ai_et_CntrlReg
;
284 unsigned int ai_et_MuxVal
;
285 unsigned int ai_et_div1
, ai_et_div2
;
286 unsigned int act_chanlist
[32]; /* list of scaned channel */
287 unsigned char act_chanlist_len
; /* len of scanlist */
288 unsigned char act_chanlist_pos
; /* actual position in MUX list */
289 unsigned char da_ranges
; /* copy of D/A outpit range register */
290 unsigned int ai_scans
; /* len of scanlist */
291 unsigned int ai_n_chan
; /* how many channels is measured */
292 unsigned int *ai_chanlist
; /* actaul chanlist */
293 unsigned int ai_flags
; /* flaglist */
294 unsigned int ai_data_len
; /* len of data buffer */
295 short *ai_data
; /* data buffer */
296 unsigned int ai_timer1
; /* timers */
297 unsigned int ai_timer2
;
298 short ao_data
[4]; /* data output buffer */
299 unsigned int cnt0_write_wait
; /* after a write, wait for update of the internal state */
302 #define devpriv ((struct pci1710_private *)dev->private)
303 #define this_board ((const struct boardtype *)dev->board_ptr)
306 ==============================================================================
309 static int check_channel_list(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
310 unsigned int *chanlist
, unsigned int n_chan
);
311 static void setup_channel_list(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
312 unsigned int *chanlist
, unsigned int n_chan
, unsigned int seglen
);
313 static void start_pacer(struct comedi_device
*dev
, int mode
, unsigned int divisor1
,
314 unsigned int divisor2
);
315 static int pci1710_reset(struct comedi_device
*dev
);
316 static int pci171x_ai_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
);
318 static const unsigned int muxonechan
[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */
319 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
320 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
321 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
325 ==============================================================================
327 static int pci171x_insn_read_ai(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
328 struct comedi_insn
*insn
, unsigned int *data
)
331 #ifdef PCI171x_PARANOIDCHECK
335 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
336 devpriv
->CntrlReg
&= Control_CNT0
;
337 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
338 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
339 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
340 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
342 setup_channel_list(dev
, s
, &insn
->chanspec
, 1, 1);
344 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
345 inw(dev
->iobase
+ PCI171x_STATUS
),
346 dev
->iobase
+ PCI171x_STATUS
);
347 for (n
= 0; n
< insn
->n
; n
++) {
348 outw(0, dev
->iobase
+ PCI171x_SOFTTRG
); /* start conversion */
349 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n
,
350 inw(dev
->iobase
+ PCI171x_STATUS
));
351 /* comedi_udelay(1); */
352 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n
,
353 inw(dev
->iobase
+ PCI171x_STATUS
));
356 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
))
359 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n
,
361 inw(dev
->iobase
+ PCI171x_STATUS
));
363 comedi_error(dev
, "A/D insn timeout");
364 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
365 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
367 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n
);
371 #ifdef PCI171x_PARANOIDCHECK
372 idata
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
373 if (this_board
->cardtype
!= TYPE_PCI1713
)
374 if ((idata
& 0xf000) != devpriv
->act_chanlist
[0]) {
375 comedi_error(dev
, "A/D insn data droput!");
378 data
[n
] = idata
& 0x0fff;
380 data
[n
] = inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff;
385 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
386 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
388 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n
);
393 ==============================================================================
395 static int pci171x_insn_write_ao(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
396 struct comedi_insn
*insn
, unsigned int *data
)
398 int n
, chan
, range
, ofs
;
400 chan
= CR_CHAN(insn
->chanspec
);
401 range
= CR_RANGE(insn
->chanspec
);
403 devpriv
->da_ranges
&= 0xfb;
404 devpriv
->da_ranges
|= (range
<< 2);
405 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
408 devpriv
->da_ranges
&= 0xfe;
409 devpriv
->da_ranges
|= range
;
410 outw(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
);
414 for (n
= 0; n
< insn
->n
; n
++)
415 outw(data
[n
], dev
->iobase
+ ofs
);
417 devpriv
->ao_data
[chan
] = data
[n
];
424 ==============================================================================
426 static int pci171x_insn_read_ao(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
427 struct comedi_insn
*insn
, unsigned int *data
)
431 chan
= CR_CHAN(insn
->chanspec
);
432 for (n
= 0; n
< insn
->n
; n
++)
433 data
[n
] = devpriv
->ao_data
[chan
];
439 ==============================================================================
441 static int pci171x_insn_bits_di(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
442 struct comedi_insn
*insn
, unsigned int *data
)
444 data
[1] = inw(dev
->iobase
+ PCI171x_DI
);
450 ==============================================================================
452 static int pci171x_insn_bits_do(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
453 struct comedi_insn
*insn
, unsigned int *data
)
456 s
->state
&= ~data
[0];
457 s
->state
|= (data
[0] & data
[1]);
458 outw(s
->state
, dev
->iobase
+ PCI171x_DO
);
466 ==============================================================================
468 static int pci171x_insn_counter_read(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
469 struct comedi_insn
*insn
, unsigned int *data
)
471 unsigned int msb
, lsb
, ccntrl
;
474 ccntrl
= 0xD2; /* count only */
475 for (i
= 0; i
< insn
->n
; i
++) {
476 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
478 lsb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
479 msb
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
481 data
[0] = lsb
| (msb
<< 8);
488 ==============================================================================
490 static int pci171x_insn_counter_write(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
491 struct comedi_insn
*insn
, unsigned int *data
)
493 uint msb
, lsb
, ccntrl
, status
;
495 lsb
= data
[0] & 0x00FF;
496 msb
= (data
[0] & 0xFF00) >> 8;
498 /* write lsb, then msb */
499 outw(lsb
, dev
->iobase
+ PCI171x_CNT0
);
500 outw(msb
, dev
->iobase
+ PCI171x_CNT0
);
502 if (devpriv
->cnt0_write_wait
) {
503 /* wait for the new count to be loaded */
506 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
507 status
= inw(dev
->iobase
+ PCI171x_CNT0
) & 0xFF;
508 } while (status
& 0x40);
515 ==============================================================================
517 static int pci171x_insn_counter_config(struct comedi_device
*dev
,
518 struct comedi_subdevice
*s
, struct comedi_insn
*insn
, unsigned int *data
)
521 /* This doesn't work like a normal Comedi counter config */
524 devpriv
->cnt0_write_wait
= data
[0] & 0x20;
526 /* internal or external clock? */
527 if (!(data
[0] & 0x10)) { /* internal */
528 devpriv
->CntrlReg
&= ~Control_CNT0
;
530 devpriv
->CntrlReg
|= Control_CNT0
;
532 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
535 ccntrl
|= Counter_M0
;
537 ccntrl
|= Counter_M1
;
539 ccntrl
|= Counter_M2
;
541 ccntrl
|= Counter_BCD
;
542 ccntrl
|= Counter_RW0
; /* set read/write mode */
543 ccntrl
|= Counter_RW1
;
544 outw(ccntrl
, dev
->iobase
+ PCI171x_CNTCTRL
);
551 ==============================================================================
553 static int pci1720_insn_write_ao(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
554 struct comedi_insn
*insn
, unsigned int *data
)
556 int n
, rangereg
, chan
;
558 chan
= CR_CHAN(insn
->chanspec
);
559 rangereg
= devpriv
->da_ranges
& (~(0x03 << (chan
<< 1)));
560 rangereg
|= (CR_RANGE(insn
->chanspec
) << (chan
<< 1));
561 if (rangereg
!= devpriv
->da_ranges
) {
562 outb(rangereg
, dev
->iobase
+ PCI1720_RANGE
);
563 devpriv
->da_ranges
= rangereg
;
566 for (n
= 0; n
< insn
->n
; n
++) {
567 outw(data
[n
], dev
->iobase
+ PCI1720_DA0
+ (chan
<< 1));
568 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
571 devpriv
->ao_data
[chan
] = data
[n
];
577 ==============================================================================
579 static void interrupt_pci1710_every_sample(void *d
)
581 struct comedi_device
*dev
= d
;
582 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
584 #ifdef PCI171x_PARANOIDCHECK
588 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
589 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
591 rt_printk("comedi%d: A/D FIFO empty (%4x)\n", dev
->minor
, m
);
592 pci171x_ai_cancel(dev
, s
);
593 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
594 comedi_event(dev
, s
);
599 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
601 pci171x_ai_cancel(dev
, s
);
602 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
603 comedi_event(dev
, s
);
607 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
610 for (; !(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_FE
);) {
611 #ifdef PCI171x_PARANOIDCHECK
612 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
613 DPRINTK("%04x:", sampl
);
614 if (this_board
->cardtype
!= TYPE_PCI1713
)
615 if ((sampl
& 0xf000) !=
616 devpriv
->act_chanlist
[s
->async
->cur_chan
]) {
618 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
619 (sampl
& 0xf000) >> 12,
620 (devpriv
->act_chanlist
[s
->async
->
621 cur_chan
] & 0xf000) >>
623 pci171x_ai_cancel(dev
, s
);
625 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
626 comedi_event(dev
, s
);
629 DPRINTK("%8d %2d %8d~", s
->async
->buf_int_ptr
,
630 s
->async
->cur_chan
, s
->async
->buf_int_count
);
631 comedi_buf_put(s
->async
, sampl
& 0x0fff);
633 comedi_buf_put(s
->async
,
634 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
636 ++s
->async
->cur_chan
;
638 if (s
->async
->cur_chan
>= devpriv
->ai_n_chan
) {
639 s
->async
->cur_chan
= 0;
642 if (s
->async
->cur_chan
== 0) { /* one scan done */
643 devpriv
->ai_act_scan
++;
644 DPRINTK("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n", s
->async
->buf_int_count
, s
->async
->buf_int_ptr
, s
->async
->buf_user_count
, s
->async
->buf_user_ptr
);
645 DPRINTK("adv_pci1710 EDBG: EOS2\n");
646 if ((!devpriv
->neverending_ai
) && (devpriv
->ai_act_scan
>= devpriv
->ai_scans
)) { /* all data sampled */
647 pci171x_ai_cancel(dev
, s
);
648 s
->async
->events
|= COMEDI_CB_EOA
;
649 comedi_event(dev
, s
);
655 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
656 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
658 comedi_event(dev
, s
);
662 ==============================================================================
664 static int move_block_from_fifo(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
668 #ifdef PCI171x_PARANOIDCHECK
671 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n
,
673 j
= s
->async
->cur_chan
;
674 for (i
= 0; i
< n
; i
++) {
675 #ifdef PCI171x_PARANOIDCHECK
676 sampl
= inw(dev
->iobase
+ PCI171x_AD_DATA
);
677 if (this_board
->cardtype
!= TYPE_PCI1713
)
678 if ((sampl
& 0xf000) != devpriv
->act_chanlist
[j
]) {
680 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
681 dev
->minor
, (sampl
& 0xf000) >> 12,
683 act_chanlist
[j
] & 0xf000) >> 12,
684 i
, j
, devpriv
->ai_act_scan
, n
, turn
,
686 pci171x_ai_cancel(dev
, s
);
688 COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
689 comedi_event(dev
, s
);
692 comedi_buf_put(s
->async
, sampl
& 0x0fff);
694 comedi_buf_put(s
->async
,
695 inw(dev
->iobase
+ PCI171x_AD_DATA
) & 0x0fff);
698 if (j
>= devpriv
->ai_n_chan
) {
700 devpriv
->ai_act_scan
++;
703 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
708 ==============================================================================
710 static void interrupt_pci1710_half_fifo(void *d
)
712 struct comedi_device
*dev
= d
;
713 struct comedi_subdevice
*s
= dev
->subdevices
+ 0;
716 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
717 m
= inw(dev
->iobase
+ PCI171x_STATUS
);
718 if (!(m
& Status_FH
)) {
719 rt_printk("comedi%d: A/D FIFO not half full! (%4x)\n",
721 pci171x_ai_cancel(dev
, s
);
722 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
723 comedi_event(dev
, s
);
728 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
730 pci171x_ai_cancel(dev
, s
);
731 s
->async
->events
|= COMEDI_CB_EOA
| COMEDI_CB_ERROR
;
732 comedi_event(dev
, s
);
736 samplesinbuf
= this_board
->fifo_half_size
;
737 if (samplesinbuf
* sizeof(short) >= devpriv
->ai_data_len
) {
738 m
= devpriv
->ai_data_len
/ sizeof(short);
739 if (move_block_from_fifo(dev
, s
, m
, 0))
745 if (move_block_from_fifo(dev
, s
, samplesinbuf
, 1))
749 if (!devpriv
->neverending_ai
)
750 if (devpriv
->ai_act_scan
>= devpriv
->ai_scans
) { /* all data sampled */
751 pci171x_ai_cancel(dev
, s
);
752 s
->async
->events
|= COMEDI_CB_EOA
;
753 comedi_event(dev
, s
);
756 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear our INT request */
757 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
759 comedi_event(dev
, s
);
763 ==============================================================================
765 static irqreturn_t
interrupt_service_pci1710(int irq
, void *d
)
767 struct comedi_device
*dev
= d
;
769 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
771 if (!dev
->attached
) /* is device attached? */
772 return IRQ_NONE
; /* no, exit */
774 if (!(inw(dev
->iobase
+ PCI171x_STATUS
) & Status_IRQ
)) /* is this interrupt from our board? */
775 return IRQ_NONE
; /* no, exit */
777 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
778 inw(dev
->iobase
+ PCI171x_STATUS
));
780 if (devpriv
->ai_et
) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
782 devpriv
->CntrlReg
&= Control_CNT0
;
783 devpriv
->CntrlReg
|= Control_SW
; /* set software trigger */
784 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
785 devpriv
->CntrlReg
= devpriv
->ai_et_CntrlReg
;
786 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
787 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
788 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
);
789 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
791 start_pacer(dev
, 1, devpriv
->ai_et_div1
, devpriv
->ai_et_div2
);
794 if (devpriv
->ai_eos
) { /* We use FIFO half full INT or not? */
795 interrupt_pci1710_every_sample(d
);
797 interrupt_pci1710_half_fifo(d
);
799 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
804 ==============================================================================
806 static int pci171x_ai_docmd_and_mode(int mode
, struct comedi_device
*dev
,
807 struct comedi_subdevice
*s
)
809 unsigned int divisor1
, divisor2
;
812 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
814 start_pacer(dev
, -1, 0, 0); /* stop pacer */
816 seglen
= check_channel_list(dev
, s
, devpriv
->ai_chanlist
,
820 setup_channel_list(dev
, s
, devpriv
->ai_chanlist
,
821 devpriv
->ai_n_chan
, seglen
);
823 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
824 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
826 devpriv
->ai_do
= mode
;
828 devpriv
->ai_act_scan
= 0;
829 s
->async
->cur_chan
= 0;
830 devpriv
->ai_buf_ptr
= 0;
831 devpriv
->neverending_ai
= 0;
833 devpriv
->CntrlReg
&= Control_CNT0
;
834 if ((devpriv
->ai_flags
& TRIG_WAKE_EOS
)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
837 devpriv
->CntrlReg
|= Control_ONEFH
;
841 if ((devpriv
->ai_scans
== 0) || (devpriv
->ai_scans
== -1)) {
842 devpriv
->neverending_ai
= 1;
843 } /* well, user want neverending */
845 devpriv
->neverending_ai
= 0;
850 if (devpriv
->ai_timer1
< this_board
->ai_ns_min
)
851 devpriv
->ai_timer1
= this_board
->ai_ns_min
;
852 devpriv
->CntrlReg
|= Control_PACER
| Control_IRQEN
;
854 devpriv
->ai_et_CntrlReg
= devpriv
->CntrlReg
;
856 ~(Control_PACER
| Control_ONEFH
| Control_GATE
);
857 devpriv
->CntrlReg
|= Control_EXT
;
862 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
863 &divisor2
, &devpriv
->ai_timer1
,
864 devpriv
->ai_flags
& TRIG_ROUND_MASK
);
865 DPRINTK("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n", devpriv
->i8254_osc_base
, divisor1
, divisor2
, devpriv
->ai_timer1
);
866 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
869 start_pacer(dev
, mode
, divisor1
, divisor2
);
871 devpriv
->ai_et_div1
= divisor1
;
872 devpriv
->ai_et_div2
= divisor2
;
876 devpriv
->CntrlReg
|= Control_EXT
| Control_IRQEN
;
877 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
);
881 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
885 #ifdef PCI171X_EXTDEBUG
887 ==============================================================================
889 static void pci171x_cmdtest_out(int e
, struct comedi_cmd
*cmd
)
891 rt_printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e
,
892 cmd
->start_src
, cmd
->scan_begin_src
, cmd
->convert_src
);
893 rt_printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e
,
894 cmd
->start_arg
, cmd
->scan_begin_arg
, cmd
->convert_arg
);
895 rt_printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e
, cmd
->stop_src
,
897 rt_printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
898 e
, cmd
->stop_arg
, cmd
->scan_end_arg
, cmd
->chanlist_len
);
903 ==============================================================================
905 static int pci171x_ai_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
906 struct comedi_cmd
*cmd
)
909 int tmp
, divisor1
, divisor2
;
911 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
912 #ifdef PCI171X_EXTDEBUG
913 pci171x_cmdtest_out(-1, cmd
);
915 /* step 1: make sure trigger sources are trivially valid */
917 tmp
= cmd
->start_src
;
918 cmd
->start_src
&= TRIG_NOW
| TRIG_EXT
;
919 if (!cmd
->start_src
|| tmp
!= cmd
->start_src
)
922 tmp
= cmd
->scan_begin_src
;
923 cmd
->scan_begin_src
&= TRIG_FOLLOW
;
924 if (!cmd
->scan_begin_src
|| tmp
!= cmd
->scan_begin_src
)
927 tmp
= cmd
->convert_src
;
928 cmd
->convert_src
&= TRIG_TIMER
| TRIG_EXT
;
929 if (!cmd
->convert_src
|| tmp
!= cmd
->convert_src
)
932 tmp
= cmd
->scan_end_src
;
933 cmd
->scan_end_src
&= TRIG_COUNT
;
934 if (!cmd
->scan_end_src
|| tmp
!= cmd
->scan_end_src
)
938 cmd
->stop_src
&= TRIG_COUNT
| TRIG_NONE
;
939 if (!cmd
->stop_src
|| tmp
!= cmd
->stop_src
)
943 #ifdef PCI171X_EXTDEBUG
944 pci171x_cmdtest_out(1, cmd
);
946 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n", err
);
950 /* step 2: make sure trigger sources are unique and mutually compatible */
952 if (cmd
->start_src
!= TRIG_NOW
&& cmd
->start_src
!= TRIG_EXT
) {
953 cmd
->start_src
= TRIG_NOW
;
957 if (cmd
->scan_begin_src
!= TRIG_FOLLOW
) {
958 cmd
->scan_begin_src
= TRIG_FOLLOW
;
962 if (cmd
->convert_src
!= TRIG_TIMER
&& cmd
->convert_src
!= TRIG_EXT
)
965 if (cmd
->scan_end_src
!= TRIG_COUNT
) {
966 cmd
->scan_end_src
= TRIG_COUNT
;
970 if (cmd
->stop_src
!= TRIG_NONE
&& cmd
->stop_src
!= TRIG_COUNT
)
974 #ifdef PCI171X_EXTDEBUG
975 pci171x_cmdtest_out(2, cmd
);
977 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n", err
);
981 /* step 3: make sure arguments are trivially compatible */
983 if (cmd
->start_arg
!= 0) {
988 if (cmd
->scan_begin_arg
!= 0) {
989 cmd
->scan_begin_arg
= 0;
993 if (cmd
->convert_src
== TRIG_TIMER
) {
994 if (cmd
->convert_arg
< this_board
->ai_ns_min
) {
995 cmd
->convert_arg
= this_board
->ai_ns_min
;
998 } else { /* TRIG_FOLLOW */
999 if (cmd
->convert_arg
!= 0) {
1000 cmd
->convert_arg
= 0;
1005 if (!cmd
->chanlist_len
) {
1006 cmd
->chanlist_len
= 1;
1009 if (cmd
->chanlist_len
> this_board
->n_aichan
) {
1010 cmd
->chanlist_len
= this_board
->n_aichan
;
1013 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
1014 cmd
->scan_end_arg
= cmd
->chanlist_len
;
1017 if (cmd
->stop_src
== TRIG_COUNT
) {
1018 if (!cmd
->stop_arg
) {
1022 } else { /* TRIG_NONE */
1023 if (cmd
->stop_arg
!= 0) {
1030 #ifdef PCI171X_EXTDEBUG
1031 pci171x_cmdtest_out(3, cmd
);
1033 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n", err
);
1037 /* step 4: fix up any arguments */
1039 if (cmd
->convert_src
== TRIG_TIMER
) {
1040 tmp
= cmd
->convert_arg
;
1041 i8253_cascade_ns_to_timer(devpriv
->i8254_osc_base
, &divisor1
,
1042 &divisor2
, &cmd
->convert_arg
,
1043 cmd
->flags
& TRIG_ROUND_MASK
);
1044 if (cmd
->convert_arg
< this_board
->ai_ns_min
)
1045 cmd
->convert_arg
= this_board
->ai_ns_min
;
1046 if (tmp
!= cmd
->convert_arg
)
1051 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n", err
);
1055 /* step 5: complain about special chanlist considerations */
1057 if (cmd
->chanlist
) {
1058 if (!check_channel_list(dev
, s
, cmd
->chanlist
,
1060 return 5; /* incorrect channels list */
1063 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1068 ==============================================================================
1070 static int pci171x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1072 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1074 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1075 devpriv
->ai_n_chan
= cmd
->chanlist_len
;
1076 devpriv
->ai_chanlist
= cmd
->chanlist
;
1077 devpriv
->ai_flags
= cmd
->flags
;
1078 devpriv
->ai_data_len
= s
->async
->prealloc_bufsz
;
1079 devpriv
->ai_data
= s
->async
->prealloc_buf
;
1080 devpriv
->ai_timer1
= 0;
1081 devpriv
->ai_timer2
= 0;
1083 if (cmd
->stop_src
== TRIG_COUNT
) {
1084 devpriv
->ai_scans
= cmd
->stop_arg
;
1086 devpriv
->ai_scans
= 0;
1089 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) { /* mode 1, 2, 3 */
1090 if (cmd
->convert_src
== TRIG_TIMER
) { /* mode 1 and 2 */
1091 devpriv
->ai_timer1
= cmd
->convert_arg
;
1092 return pci171x_ai_docmd_and_mode(cmd
->start_src
==
1093 TRIG_EXT
? 2 : 1, dev
, s
);
1095 if (cmd
->convert_src
== TRIG_EXT
) { /* mode 3 */
1096 return pci171x_ai_docmd_and_mode(3, dev
, s
);
1104 ==============================================================================
1105 Check if channel list from user is builded correctly
1106 If it's ok, then program scan/gain logic.
1107 This works for all cards.
1109 static int check_channel_list(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1110 unsigned int *chanlist
, unsigned int n_chan
)
1112 unsigned int chansegment
[32];
1113 unsigned int i
, nowmustbechan
, seglen
, segpos
;
1115 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan
);
1116 /* correct channel and range number check itself comedi/range.c */
1118 comedi_error(dev
, "range/channel list is empty!");
1123 chansegment
[0] = chanlist
[0]; /* first channel is everytime ok */
1124 for (i
= 1, seglen
= 1; i
< n_chan
; i
++, seglen
++) { /* build part of chanlist */
1125 /* rt_printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1126 if (chanlist
[0] == chanlist
[i
])
1127 break; /* we detect loop, this must by finish */
1128 if (CR_CHAN(chanlist
[i
]) & 1) /* odd channel cann't by differencial */
1129 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
) {
1131 "Odd channel can't be differential input!\n");
1135 (CR_CHAN(chansegment
[i
- 1]) + 1) % s
->n_chan
;
1136 if (CR_AREF(chansegment
[i
- 1]) == AREF_DIFF
)
1137 nowmustbechan
= (nowmustbechan
+ 1) % s
->n_chan
;
1138 if (nowmustbechan
!= CR_CHAN(chanlist
[i
])) { /* channel list isn't continous :-( */
1140 ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1141 i
, CR_CHAN(chanlist
[i
]), nowmustbechan
,
1142 CR_CHAN(chanlist
[0]));
1145 chansegment
[i
] = chanlist
[i
]; /* well, this is next correct channel in list */
1148 for (i
= 0, segpos
= 0; i
< n_chan
; i
++) { /* check whole chanlist */
1149 /* rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1150 if (chanlist
[i
] != chansegment
[i
% seglen
]) {
1152 ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1153 i
, CR_CHAN(chansegment
[i
]),
1154 CR_RANGE(chansegment
[i
]),
1155 CR_AREF(chansegment
[i
]),
1156 CR_CHAN(chanlist
[i
% seglen
]),
1157 CR_RANGE(chanlist
[i
% seglen
]),
1158 CR_AREF(chansegment
[i
% seglen
]));
1159 return 0; /* chan/gain list is strange */
1168 static void setup_channel_list(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1169 unsigned int *chanlist
, unsigned int n_chan
, unsigned int seglen
)
1171 unsigned int i
, range
, chanprog
;
1173 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan
,
1175 devpriv
->act_chanlist_len
= seglen
;
1176 devpriv
->act_chanlist_pos
= 0;
1178 DPRINTK("SegLen: %d\n", seglen
);
1179 for (i
= 0; i
< seglen
; i
++) { /* store range list to card */
1180 chanprog
= muxonechan
[CR_CHAN(chanlist
[i
])];
1181 outw(chanprog
, dev
->iobase
+ PCI171x_MUX
); /* select channel */
1182 range
= this_board
->rangecode_ai
[CR_RANGE(chanlist
[i
])];
1183 if (CR_AREF(chanlist
[i
]) == AREF_DIFF
)
1185 outw(range
, dev
->iobase
+ PCI171x_RANGE
); /* select gain */
1186 #ifdef PCI171x_PARANOIDCHECK
1187 devpriv
->act_chanlist
[i
] =
1188 (CR_CHAN(chanlist
[i
]) << 12) & 0xf000;
1190 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i
, chanprog
, range
,
1191 devpriv
->act_chanlist
[i
]);
1194 devpriv
->ai_et_MuxVal
=
1195 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8);
1196 outw(devpriv
->ai_et_MuxVal
, dev
->iobase
+ PCI171x_MUX
); /* select channel interval to scan */
1197 DPRINTK("MUX: %4x L%4x.H%4x\n",
1198 CR_CHAN(chanlist
[0]) | (CR_CHAN(chanlist
[seglen
- 1]) << 8),
1199 CR_CHAN(chanlist
[0]), CR_CHAN(chanlist
[seglen
- 1]));
1203 ==============================================================================
1205 static void start_pacer(struct comedi_device
*dev
, int mode
, unsigned int divisor1
,
1206 unsigned int divisor2
)
1208 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode
,
1209 divisor1
, divisor2
);
1210 outw(0xb4, dev
->iobase
+ PCI171x_CNTCTRL
);
1211 outw(0x74, dev
->iobase
+ PCI171x_CNTCTRL
);
1214 outw(divisor2
& 0xff, dev
->iobase
+ PCI171x_CNT2
);
1215 outw((divisor2
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT2
);
1216 outw(divisor1
& 0xff, dev
->iobase
+ PCI171x_CNT1
);
1217 outw((divisor1
>> 8) & 0xff, dev
->iobase
+ PCI171x_CNT1
);
1219 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1223 ==============================================================================
1225 static int pci171x_ai_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1227 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1229 switch (this_board
->cardtype
) {
1231 devpriv
->CntrlReg
&= Control_CNT0
;
1232 devpriv
->CntrlReg
|= Control_SW
;
1234 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1235 start_pacer(dev
, -1, 0, 0);
1236 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
);
1237 outb(0, dev
->iobase
+ PCI171x_CLRINT
);
1242 devpriv
->ai_act_scan
= 0;
1243 s
->async
->cur_chan
= 0;
1244 devpriv
->ai_buf_ptr
= 0;
1245 devpriv
->neverending_ai
= 0;
1247 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1252 ==============================================================================
1254 static int pci171x_reset(struct comedi_device
*dev
)
1256 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1257 outw(0x30, dev
->iobase
+ PCI171x_CNTCTRL
);
1258 devpriv
->CntrlReg
= Control_SW
| Control_CNT0
; /* Software trigger, CNT0=external */
1259 outw(devpriv
->CntrlReg
, dev
->iobase
+ PCI171x_CONTROL
); /* reset any operations */
1260 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1261 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1262 start_pacer(dev
, -1, 0, 0); /* stop 8254 */
1263 devpriv
->da_ranges
= 0;
1264 if (this_board
->n_aochan
) {
1265 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI171x_DAREF
); /* set DACs to 0..5V */
1266 outw(0, dev
->iobase
+ PCI171x_DA1
); /* set DA outputs to 0V */
1267 devpriv
->ao_data
[0] = 0x0000;
1268 if (this_board
->n_aochan
> 1) {
1269 outw(0, dev
->iobase
+ PCI171x_DA2
);
1270 devpriv
->ao_data
[1] = 0x0000;
1273 outw(0, dev
->iobase
+ PCI171x_DO
); /* digital outputs to 0 */
1274 outb(0, dev
->iobase
+ PCI171x_CLRFIFO
); /* clear FIFO */
1275 outb(0, dev
->iobase
+ PCI171x_CLRINT
); /* clear INT request */
1277 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1282 ==============================================================================
1284 static int pci1720_reset(struct comedi_device
*dev
)
1286 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1287 outb(Syncont_SC0
, dev
->iobase
+ PCI1720_SYNCONT
); /* set synchronous output mode */
1288 devpriv
->da_ranges
= 0xAA;
1289 outb(devpriv
->da_ranges
, dev
->iobase
+ PCI1720_RANGE
); /* set all ranges to +/-5V */
1290 outw(0x0800, dev
->iobase
+ PCI1720_DA0
); /* set outputs to 0V */
1291 outw(0x0800, dev
->iobase
+ PCI1720_DA1
);
1292 outw(0x0800, dev
->iobase
+ PCI1720_DA2
);
1293 outw(0x0800, dev
->iobase
+ PCI1720_DA3
);
1294 outb(0, dev
->iobase
+ PCI1720_SYNCOUT
); /* update outputs */
1295 devpriv
->ao_data
[0] = 0x0800;
1296 devpriv
->ao_data
[1] = 0x0800;
1297 devpriv
->ao_data
[2] = 0x0800;
1298 devpriv
->ao_data
[3] = 0x0800;
1299 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1304 ==============================================================================
1306 static int pci1710_reset(struct comedi_device
*dev
)
1308 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1309 switch (this_board
->cardtype
) {
1311 return pci1720_reset(dev
);
1313 return pci171x_reset(dev
);
1315 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1319 ==============================================================================
1321 static int pci1710_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
1323 struct comedi_subdevice
*s
;
1324 int ret
, subdev
, n_subdevices
;
1326 unsigned long iobase
;
1327 struct pci_dev
*pcidev
;
1328 int opt_bus
, opt_slot
;
1330 unsigned char pci_bus
, pci_slot
, pci_func
;
1334 rt_printk("comedi%d: adv_pci1710: ", dev
->minor
);
1336 opt_bus
= it
->options
[0];
1337 opt_slot
= it
->options
[1];
1339 ret
= alloc_private(dev
, sizeof(struct pci1710_private
));
1341 rt_printk(" - Allocation failed!\n");
1345 /* Look for matching PCI device */
1346 errstr
= "not found!";
1348 board_index
= this_board
- boardtypes
;
1349 while (NULL
!= (pcidev
= pci_get_device(PCI_VENDOR_ID_ADVANTECH
,
1350 PCI_ANY_ID
, pcidev
))) {
1351 if (strcmp (this_board
->name
, DRV_NAME
) == 0)
1353 for (i
= 0; i
< n_boardtypes
; ++i
)
1355 if (pcidev
->device
== boardtypes
[i
].device_id
)
1361 if (i
== n_boardtypes
) continue;
1364 if (pcidev
->device
!= boardtypes
[board_index
].device_id
) continue;
1367 /* Found matching vendor/device. */
1368 if (opt_bus
|| opt_slot
) {
1369 /* Check bus/slot. */
1370 if (opt_bus
!= pcidev
->bus
->number
1371 || opt_slot
!= PCI_SLOT(pcidev
->devfn
))
1372 continue; /* no match */
1375 * Look for device that isn't in use.
1376 * Enable PCI device and request regions.
1378 if (comedi_pci_enable(pcidev
, DRV_NAME
)) {
1379 errstr
= "failed to enable PCI device and request regions!";
1382 /* fixup board_ptr in case we were using the dummy entry with the driver name */
1383 dev
->board_ptr
= &boardtypes
[board_index
];
1388 if (opt_bus
|| opt_slot
) {
1389 rt_printk(" - Card at b:s %d:%d %s\n",
1390 opt_bus
, opt_slot
, errstr
);
1392 rt_printk(" - Card %s\n", errstr
);
1397 pci_bus
= pcidev
->bus
->number
;
1398 pci_slot
= PCI_SLOT(pcidev
->devfn
);
1399 pci_func
= PCI_FUNC(pcidev
->devfn
);
1401 iobase
= pci_resource_start(pcidev
, 2);
1403 rt_printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus
, pci_slot
, pci_func
,
1406 dev
->iobase
= iobase
;
1408 dev
->board_name
= this_board
->name
;
1409 devpriv
->pcidev
= pcidev
;
1412 if (this_board
->n_aichan
)
1414 if (this_board
->n_aochan
)
1416 if (this_board
->n_dichan
)
1418 if (this_board
->n_dochan
)
1420 if (this_board
->n_counter
)
1423 ret
= alloc_subdevices(dev
, n_subdevices
);
1425 rt_printk(" - Allocation failed!\n");
1431 if (this_board
->have_irq
) {
1433 if (comedi_request_irq(irq
, interrupt_service_pci1710
,
1434 IRQF_SHARED
, "Advantech PCI-1710",
1437 (", unable to allocate IRQ %d, DISABLING IT",
1439 irq
= 0; /* Can't use IRQ */
1441 rt_printk(", irq=%u", irq
);
1444 rt_printk(", IRQ disabled");
1456 if (this_board
->n_aichan
) {
1457 s
= dev
->subdevices
+ subdev
;
1458 dev
->read_subdev
= s
;
1459 s
->type
= COMEDI_SUBD_AI
;
1460 s
->subdev_flags
= SDF_READABLE
| SDF_COMMON
| SDF_GROUND
;
1461 if (this_board
->n_aichand
)
1462 s
->subdev_flags
|= SDF_DIFF
;
1463 s
->n_chan
= this_board
->n_aichan
;
1464 s
->maxdata
= this_board
->ai_maxdata
;
1465 s
->len_chanlist
= this_board
->n_aichan
;
1466 s
->range_table
= this_board
->rangelist_ai
;
1467 s
->cancel
= pci171x_ai_cancel
;
1468 s
->insn_read
= pci171x_insn_read_ai
;
1470 s
->subdev_flags
|= SDF_CMD_READ
;
1471 s
->do_cmdtest
= pci171x_ai_cmdtest
;
1472 s
->do_cmd
= pci171x_ai_cmd
;
1474 devpriv
->i8254_osc_base
= 100; /* 100ns=10MHz */
1478 if (this_board
->n_aochan
) {
1479 s
= dev
->subdevices
+ subdev
;
1480 s
->type
= COMEDI_SUBD_AO
;
1481 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1482 s
->n_chan
= this_board
->n_aochan
;
1483 s
->maxdata
= this_board
->ao_maxdata
;
1484 s
->len_chanlist
= this_board
->n_aochan
;
1485 s
->range_table
= this_board
->rangelist_ao
;
1486 switch (this_board
->cardtype
) {
1488 s
->insn_write
= pci1720_insn_write_ao
;
1491 s
->insn_write
= pci171x_insn_write_ao
;
1494 s
->insn_read
= pci171x_insn_read_ao
;
1498 if (this_board
->n_dichan
) {
1499 s
= dev
->subdevices
+ subdev
;
1500 s
->type
= COMEDI_SUBD_DI
;
1501 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_COMMON
;
1502 s
->n_chan
= this_board
->n_dichan
;
1504 s
->len_chanlist
= this_board
->n_dichan
;
1505 s
->range_table
= &range_digital
;
1506 s
->io_bits
= 0; /* all bits input */
1507 s
->insn_bits
= pci171x_insn_bits_di
;
1511 if (this_board
->n_dochan
) {
1512 s
= dev
->subdevices
+ subdev
;
1513 s
->type
= COMEDI_SUBD_DO
;
1514 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
1515 s
->n_chan
= this_board
->n_dochan
;
1517 s
->len_chanlist
= this_board
->n_dochan
;
1518 s
->range_table
= &range_digital
;
1519 s
->io_bits
= (1 << this_board
->n_dochan
) - 1; /* all bits output */
1521 s
->insn_bits
= pci171x_insn_bits_do
;
1525 if (this_board
->n_counter
) {
1526 s
= dev
->subdevices
+ subdev
;
1527 s
->type
= COMEDI_SUBD_COUNTER
;
1528 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
1529 s
->n_chan
= this_board
->n_counter
;
1530 s
->len_chanlist
= this_board
->n_counter
;
1531 s
->maxdata
= 0xffff;
1532 s
->range_table
= &range_unknown
;
1533 s
->insn_read
= pci171x_insn_counter_read
;
1534 s
->insn_write
= pci171x_insn_counter_write
;
1535 s
->insn_config
= pci171x_insn_counter_config
;
1545 ==============================================================================
1547 static int pci1710_detach(struct comedi_device
*dev
)
1554 comedi_free_irq(dev
->irq
, dev
);
1555 if (devpriv
->pcidev
) {
1557 comedi_pci_disable(devpriv
->pcidev
);
1559 pci_dev_put(devpriv
->pcidev
);
1567 ==============================================================================
1569 COMEDI_PCI_INITCLEANUP(driver_pci1710
, pci1710_pci_table
);
1571 ==============================================================================