GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / comedi / drivers / adv_pci1710.c
blobbdd6954cad96f5b863d1cf22cf3a189aa43e120e
1 /*
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
13 * Options:
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
20 Driver: adv_pci1710
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,
26 PCI-1731
27 Status: works
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
35 PCI driver.
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
41 device will be used.
44 #include <linux/interrupt.h>
46 #include "../comedidev.h"
48 #include "comedi_pci.h"
50 #include "8253.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
55 * sample */
57 #undef PCI171X_EXTDEBUG
59 #define DRV_NAME "adv_pci1710"
61 #undef DPRINTK
62 #ifdef PCI171X_EXTDEBUG
63 #define DPRINTK(fmt, args...) printk(fmt, ## args)
64 #else
65 #define DPRINTK(fmt, args...)
66 #endif
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
97 * reg) */
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 occured */
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, {
134 BIP_RANGE(5),
135 BIP_RANGE(2.5),
136 BIP_RANGE(1.25),
137 BIP_RANGE(0.625),
138 BIP_RANGE(10),
139 UNI_RANGE(10),
140 UNI_RANGE(5),
141 UNI_RANGE(2.5),
142 UNI_RANGE(1.25)
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, {
150 BIP_RANGE(5),
151 BIP_RANGE(0.5),
152 BIP_RANGE(0.05),
153 BIP_RANGE(0.005),
154 BIP_RANGE(10),
155 BIP_RANGE(1),
156 BIP_RANGE(0.1),
157 BIP_RANGE(0.01),
158 UNI_RANGE(10),
159 UNI_RANGE(1),
160 UNI_RANGE(0.1),
161 UNI_RANGE(0.01)
165 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
166 0x05, 0x06, 0x07, 0x10, 0x11,
167 0x12, 0x13 };
169 static const struct comedi_lrange range_pci17x1 = { 5, {
170 BIP_RANGE(10),
171 BIP_RANGE(5),
172 BIP_RANGE(2.5),
173 BIP_RANGE(1.25),
174 BIP_RANGE(0.625)
178 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
180 static const struct comedi_lrange range_pci1720 = { 4, {
181 UNI_RANGE(5),
182 UNI_RANGE(10),
183 BIP_RANGE(5),
184 BIP_RANGE(10)
188 static const struct comedi_lrange range_pci171x_da = { 2, {
189 UNI_RANGE(5),
190 UNI_RANGE(10),
194 static int pci1710_attach(struct comedi_device *dev,
195 struct comedi_devconfig *it);
196 static int pci1710_detach(struct comedi_device *dev);
198 struct boardtype {
199 const char *name; /* board name */
200 int device_id;
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) = {
221 PCI_VENDOR_ID_ADVANTECH, 0x1710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
222 PCI_VENDOR_ID_ADVANTECH, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
223 PCI_VENDOR_ID_ADVANTECH, 0x1713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
224 PCI_VENDOR_ID_ADVANTECH, 0x1720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
225 PCI_VENDOR_ID_ADVANTECH, 0x1731, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
229 MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
231 static const struct boardtype boardtypes[] = {
232 {"pci1710", 0x1710,
233 IORANGE_171x, 1, TYPE_PCI171X,
234 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
235 &range_pci1710_3, range_codes_pci1710_3,
236 &range_pci171x_da,
237 10000, 2048},
238 {"pci1710hg", 0x1710,
239 IORANGE_171x, 1, TYPE_PCI171X,
240 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
241 &range_pci1710hg, range_codes_pci1710hg,
242 &range_pci171x_da,
243 10000, 2048},
244 {"pci1711", 0x1711,
245 IORANGE_171x, 1, TYPE_PCI171X,
246 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
247 &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
248 10000, 512},
249 {"pci1713", 0x1713,
250 IORANGE_171x, 1, TYPE_PCI1713,
251 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
252 &range_pci1710_3, range_codes_pci1710_3, NULL,
253 10000, 2048},
254 {"pci1720", 0x1720,
255 IORANGE_1720, 0, TYPE_PCI1720,
256 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
257 NULL, NULL, &range_pci1720,
258 0, 0},
259 {"pci1731", 0x1731,
260 IORANGE_171x, 1, TYPE_PCI171X,
261 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
262 &range_pci17x1, range_codes_pci17x1, NULL,
263 10000, 512},
264 /* dummy entry corresponding to driver name */
265 {.name = DRV_NAME},
268 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
270 static struct comedi_driver driver_pci1710 = {
271 .driver_name = DRV_NAME,
272 .module = THIS_MODULE,
273 .attach = pci1710_attach,
274 .detach = pci1710_detach,
275 .num_names = n_boardtypes,
276 .board_name = &boardtypes[0].name,
277 .offset = sizeof(struct boardtype),
280 struct pci1710_private {
281 struct pci_dev *pcidev; /* ptr to PCI device */
282 char valid; /* card is usable */
283 char neverending_ai; /* we do unlimited AI */
284 unsigned int CntrlReg; /* Control register */
285 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
286 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
287 unsigned int ai_act_scan; /* how many scans we finished */
288 unsigned int ai_act_chan; /* actual position in actual scan */
289 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
290 unsigned char ai_eos; /* 1=EOS wake up */
291 unsigned char ai_et;
292 unsigned int ai_et_CntrlReg;
293 unsigned int ai_et_MuxVal;
294 unsigned int ai_et_div1, ai_et_div2;
295 unsigned int act_chanlist[32]; /* list of scaned channel */
296 unsigned char act_chanlist_len; /* len of scanlist */
297 unsigned char act_chanlist_pos; /* actual position in MUX list */
298 unsigned char da_ranges; /* copy of D/A outpit range register */
299 unsigned int ai_scans; /* len of scanlist */
300 unsigned int ai_n_chan; /* how many channels is measured */
301 unsigned int *ai_chanlist; /* actaul chanlist */
302 unsigned int ai_flags; /* flaglist */
303 unsigned int ai_data_len; /* len of data buffer */
304 short *ai_data; /* data buffer */
305 unsigned int ai_timer1; /* timers */
306 unsigned int ai_timer2;
307 short ao_data[4]; /* data output buffer */
308 unsigned int cnt0_write_wait; /* after a write, wait for update of the
309 * internal state */
312 #define devpriv ((struct pci1710_private *)dev->private)
313 #define this_board ((const struct boardtype *)dev->board_ptr)
316 ==============================================================================
319 static int check_channel_list(struct comedi_device *dev,
320 struct comedi_subdevice *s,
321 unsigned int *chanlist, unsigned int n_chan);
322 static void setup_channel_list(struct comedi_device *dev,
323 struct comedi_subdevice *s,
324 unsigned int *chanlist, unsigned int n_chan,
325 unsigned int seglen);
326 static void start_pacer(struct comedi_device *dev, int mode,
327 unsigned int divisor1, unsigned int divisor2);
328 static int pci1710_reset(struct comedi_device *dev);
329 static int pci171x_ai_cancel(struct comedi_device *dev,
330 struct comedi_subdevice *s);
332 /* used for gain list programming */
333 static const unsigned int muxonechan[] = {
334 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
335 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
336 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
337 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
341 ==============================================================================
343 static int pci171x_insn_read_ai(struct comedi_device *dev,
344 struct comedi_subdevice *s,
345 struct comedi_insn *insn, unsigned int *data)
347 int n, timeout;
348 #ifdef PCI171x_PARANOIDCHECK
349 unsigned int idata;
350 #endif
352 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
353 devpriv->CntrlReg &= Control_CNT0;
354 devpriv->CntrlReg |= Control_SW; /* set software trigger */
355 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
356 outb(0, dev->iobase + PCI171x_CLRFIFO);
357 outb(0, dev->iobase + PCI171x_CLRINT);
359 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
361 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
362 inw(dev->iobase + PCI171x_STATUS),
363 dev->iobase + PCI171x_STATUS);
364 for (n = 0; n < insn->n; n++) {
365 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
366 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
367 inw(dev->iobase + PCI171x_STATUS));
368 /* udelay(1); */
369 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
370 inw(dev->iobase + PCI171x_STATUS));
371 timeout = 100;
372 while (timeout--) {
373 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
374 goto conv_finish;
375 if (!(timeout % 10))
376 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
377 timeout,
378 inw(dev->iobase + PCI171x_STATUS));
380 comedi_error(dev, "A/D insn timeout");
381 outb(0, dev->iobase + PCI171x_CLRFIFO);
382 outb(0, dev->iobase + PCI171x_CLRINT);
383 data[n] = 0;
384 DPRINTK
385 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
387 return -ETIME;
389 conv_finish:
390 #ifdef PCI171x_PARANOIDCHECK
391 idata = inw(dev->iobase + PCI171x_AD_DATA);
392 if (this_board->cardtype != TYPE_PCI1713)
393 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
394 comedi_error(dev, "A/D insn data droput!");
395 return -ETIME;
397 data[n] = idata & 0x0fff;
398 #else
399 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
400 #endif
404 outb(0, dev->iobase + PCI171x_CLRFIFO);
405 outb(0, dev->iobase + PCI171x_CLRINT);
407 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
408 return n;
412 ==============================================================================
414 static int pci171x_insn_write_ao(struct comedi_device *dev,
415 struct comedi_subdevice *s,
416 struct comedi_insn *insn, unsigned int *data)
418 int n, chan, range, ofs;
420 chan = CR_CHAN(insn->chanspec);
421 range = CR_RANGE(insn->chanspec);
422 if (chan) {
423 devpriv->da_ranges &= 0xfb;
424 devpriv->da_ranges |= (range << 2);
425 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
426 ofs = PCI171x_DA2;
427 } else {
428 devpriv->da_ranges &= 0xfe;
429 devpriv->da_ranges |= range;
430 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
431 ofs = PCI171x_DA1;
434 for (n = 0; n < insn->n; n++)
435 outw(data[n], dev->iobase + ofs);
437 devpriv->ao_data[chan] = data[n];
439 return n;
444 ==============================================================================
446 static int pci171x_insn_read_ao(struct comedi_device *dev,
447 struct comedi_subdevice *s,
448 struct comedi_insn *insn, unsigned int *data)
450 int n, chan;
452 chan = CR_CHAN(insn->chanspec);
453 for (n = 0; n < insn->n; n++)
454 data[n] = devpriv->ao_data[chan];
456 return n;
460 ==============================================================================
462 static int pci171x_insn_bits_di(struct comedi_device *dev,
463 struct comedi_subdevice *s,
464 struct comedi_insn *insn, unsigned int *data)
466 data[1] = inw(dev->iobase + PCI171x_DI);
468 return 2;
472 ==============================================================================
474 static int pci171x_insn_bits_do(struct comedi_device *dev,
475 struct comedi_subdevice *s,
476 struct comedi_insn *insn, unsigned int *data)
478 if (data[0]) {
479 s->state &= ~data[0];
480 s->state |= (data[0] & data[1]);
481 outw(s->state, dev->iobase + PCI171x_DO);
483 data[1] = s->state;
485 return 2;
489 ==============================================================================
491 static int pci171x_insn_counter_read(struct comedi_device *dev,
492 struct comedi_subdevice *s,
493 struct comedi_insn *insn,
494 unsigned int *data)
496 unsigned int msb, lsb, ccntrl;
497 int i;
499 ccntrl = 0xD2; /* count only */
500 for (i = 0; i < insn->n; i++) {
501 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
503 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
504 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
506 data[0] = lsb | (msb << 8);
509 return insn->n;
513 ==============================================================================
515 static int pci171x_insn_counter_write(struct comedi_device *dev,
516 struct comedi_subdevice *s,
517 struct comedi_insn *insn,
518 unsigned int *data)
520 uint msb, lsb, ccntrl, status;
522 lsb = data[0] & 0x00FF;
523 msb = (data[0] & 0xFF00) >> 8;
525 /* write lsb, then msb */
526 outw(lsb, dev->iobase + PCI171x_CNT0);
527 outw(msb, dev->iobase + PCI171x_CNT0);
529 if (devpriv->cnt0_write_wait) {
530 /* wait for the new count to be loaded */
531 ccntrl = 0xE2;
532 do {
533 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
534 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
535 } while (status & 0x40);
538 return insn->n;
542 ==============================================================================
544 static int pci171x_insn_counter_config(struct comedi_device *dev,
545 struct comedi_subdevice *s,
546 struct comedi_insn *insn,
547 unsigned int *data)
549 #ifdef unused
550 /* This doesn't work like a normal Comedi counter config */
551 uint ccntrl = 0;
553 devpriv->cnt0_write_wait = data[0] & 0x20;
555 /* internal or external clock? */
556 if (!(data[0] & 0x10)) { /* internal */
557 devpriv->CntrlReg &= ~Control_CNT0;
558 } else {
559 devpriv->CntrlReg |= Control_CNT0;
561 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
563 if (data[0] & 0x01)
564 ccntrl |= Counter_M0;
565 if (data[0] & 0x02)
566 ccntrl |= Counter_M1;
567 if (data[0] & 0x04)
568 ccntrl |= Counter_M2;
569 if (data[0] & 0x08)
570 ccntrl |= Counter_BCD;
571 ccntrl |= Counter_RW0; /* set read/write mode */
572 ccntrl |= Counter_RW1;
573 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
574 #endif
576 return 1;
580 ==============================================================================
582 static int pci1720_insn_write_ao(struct comedi_device *dev,
583 struct comedi_subdevice *s,
584 struct comedi_insn *insn, unsigned int *data)
586 int n, rangereg, chan;
588 chan = CR_CHAN(insn->chanspec);
589 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
590 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
591 if (rangereg != devpriv->da_ranges) {
592 outb(rangereg, dev->iobase + PCI1720_RANGE);
593 devpriv->da_ranges = rangereg;
596 for (n = 0; n < insn->n; n++) {
597 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
598 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
601 devpriv->ao_data[chan] = data[n];
603 return n;
607 ==============================================================================
609 static void interrupt_pci1710_every_sample(void *d)
611 struct comedi_device *dev = d;
612 struct comedi_subdevice *s = dev->subdevices + 0;
613 int m;
614 #ifdef PCI171x_PARANOIDCHECK
615 short sampl;
616 #endif
618 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
619 m = inw(dev->iobase + PCI171x_STATUS);
620 if (m & Status_FE) {
621 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
622 pci171x_ai_cancel(dev, s);
623 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
624 comedi_event(dev, s);
625 return;
627 if (m & Status_FF) {
628 printk
629 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
630 dev->minor, m);
631 pci171x_ai_cancel(dev, s);
632 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
633 comedi_event(dev, s);
634 return;
637 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
639 DPRINTK("FOR ");
640 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
641 #ifdef PCI171x_PARANOIDCHECK
642 sampl = inw(dev->iobase + PCI171x_AD_DATA);
643 DPRINTK("%04x:", sampl);
644 if (this_board->cardtype != TYPE_PCI1713)
645 if ((sampl & 0xf000) !=
646 devpriv->act_chanlist[s->async->cur_chan]) {
647 printk
648 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
649 (sampl & 0xf000) >> 12,
650 (devpriv->
651 act_chanlist[s->
652 async->cur_chan] & 0xf000) >>
653 12);
654 pci171x_ai_cancel(dev, s);
655 s->async->events |=
656 COMEDI_CB_EOA | COMEDI_CB_ERROR;
657 comedi_event(dev, s);
658 return;
660 DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr,
661 s->async->cur_chan, s->async->buf_int_count);
662 comedi_buf_put(s->async, sampl & 0x0fff);
663 #else
664 comedi_buf_put(s->async,
665 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
666 #endif
667 ++s->async->cur_chan;
669 if (s->async->cur_chan >= devpriv->ai_n_chan)
670 s->async->cur_chan = 0;
673 if (s->async->cur_chan == 0) { /* one scan done */
674 devpriv->ai_act_scan++;
675 DPRINTK
676 ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
677 s->async->buf_int_count, s->async->buf_int_ptr,
678 s->async->buf_user_count, s->async->buf_user_ptr);
679 DPRINTK("adv_pci1710 EDBG: EOS2\n");
680 if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */
681 pci171x_ai_cancel(dev, s);
682 s->async->events |= COMEDI_CB_EOA;
683 comedi_event(dev, s);
684 return;
689 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
690 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
692 comedi_event(dev, s);
696 ==============================================================================
698 static int move_block_from_fifo(struct comedi_device *dev,
699 struct comedi_subdevice *s, int n, int turn)
701 int i, j;
702 #ifdef PCI171x_PARANOIDCHECK
703 int sampl;
704 #endif
705 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
706 turn);
707 j = s->async->cur_chan;
708 for (i = 0; i < n; i++) {
709 #ifdef PCI171x_PARANOIDCHECK
710 sampl = inw(dev->iobase + PCI171x_AD_DATA);
711 if (this_board->cardtype != TYPE_PCI1713)
712 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
713 printk
714 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
715 dev->minor, (sampl & 0xf000) >> 12,
716 (devpriv->act_chanlist[j] & 0xf000) >> 12,
717 i, j, devpriv->ai_act_scan, n, turn,
718 sampl);
719 pci171x_ai_cancel(dev, s);
720 s->async->events |=
721 COMEDI_CB_EOA | COMEDI_CB_ERROR;
722 comedi_event(dev, s);
723 return 1;
725 comedi_buf_put(s->async, sampl & 0x0fff);
726 #else
727 comedi_buf_put(s->async,
728 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
729 #endif
730 j++;
731 if (j >= devpriv->ai_n_chan) {
732 j = 0;
733 devpriv->ai_act_scan++;
736 s->async->cur_chan = j;
737 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
738 return 0;
742 ==============================================================================
744 static void interrupt_pci1710_half_fifo(void *d)
746 struct comedi_device *dev = d;
747 struct comedi_subdevice *s = dev->subdevices + 0;
748 int m, samplesinbuf;
750 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
751 m = inw(dev->iobase + PCI171x_STATUS);
752 if (!(m & Status_FH)) {
753 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
754 dev->minor, m);
755 pci171x_ai_cancel(dev, s);
756 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
757 comedi_event(dev, s);
758 return;
760 if (m & Status_FF) {
761 printk
762 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
763 dev->minor, m);
764 pci171x_ai_cancel(dev, s);
765 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
766 comedi_event(dev, s);
767 return;
770 samplesinbuf = this_board->fifo_half_size;
771 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
772 m = devpriv->ai_data_len / sizeof(short);
773 if (move_block_from_fifo(dev, s, m, 0))
774 return;
775 samplesinbuf -= m;
778 if (samplesinbuf) {
779 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
780 return;
783 if (!devpriv->neverending_ai)
784 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
785 sampled */
786 pci171x_ai_cancel(dev, s);
787 s->async->events |= COMEDI_CB_EOA;
788 comedi_event(dev, s);
789 return;
791 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
792 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
794 comedi_event(dev, s);
798 ==============================================================================
800 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
802 struct comedi_device *dev = d;
804 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
805 irq);
806 if (!dev->attached) /* is device attached? */
807 return IRQ_NONE; /* no, exit */
809 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */
810 return IRQ_NONE; /* no, exit */
812 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
813 inw(dev->iobase + PCI171x_STATUS));
815 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
816 devpriv->ai_et = 0;
817 devpriv->CntrlReg &= Control_CNT0;
818 devpriv->CntrlReg |= Control_SW; /* set software trigger */
819 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
820 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
821 outb(0, dev->iobase + PCI171x_CLRFIFO);
822 outb(0, dev->iobase + PCI171x_CLRINT);
823 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
824 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
825 /* start pacer */
826 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
827 return IRQ_HANDLED;
829 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
830 interrupt_pci1710_every_sample(d);
831 } else {
832 interrupt_pci1710_half_fifo(d);
834 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
835 return IRQ_HANDLED;
839 ==============================================================================
841 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
842 struct comedi_subdevice *s)
844 unsigned int divisor1 = 0, divisor2 = 0;
845 unsigned int seglen;
847 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
848 mode);
849 start_pacer(dev, -1, 0, 0); /* stop pacer */
851 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
852 devpriv->ai_n_chan);
853 if (seglen < 1)
854 return -EINVAL;
855 setup_channel_list(dev, s, devpriv->ai_chanlist,
856 devpriv->ai_n_chan, seglen);
858 outb(0, dev->iobase + PCI171x_CLRFIFO);
859 outb(0, dev->iobase + PCI171x_CLRINT);
861 devpriv->ai_do = mode;
863 devpriv->ai_act_scan = 0;
864 s->async->cur_chan = 0;
865 devpriv->ai_buf_ptr = 0;
866 devpriv->neverending_ai = 0;
868 devpriv->CntrlReg &= Control_CNT0;
869 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
870 devpriv->ai_eos = 1;
871 } else {
872 devpriv->CntrlReg |= Control_ONEFH;
873 devpriv->ai_eos = 0;
876 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
877 devpriv->neverending_ai = 1;
878 /* well, user want neverending */
879 else
880 devpriv->neverending_ai = 0;
882 switch (mode) {
883 case 1:
884 case 2:
885 if (devpriv->ai_timer1 < this_board->ai_ns_min)
886 devpriv->ai_timer1 = this_board->ai_ns_min;
887 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
888 if (mode == 2) {
889 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
890 devpriv->CntrlReg &=
891 ~(Control_PACER | Control_ONEFH | Control_GATE);
892 devpriv->CntrlReg |= Control_EXT;
893 devpriv->ai_et = 1;
894 } else {
895 devpriv->ai_et = 0;
897 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
898 &divisor2, &devpriv->ai_timer1,
899 devpriv->ai_flags & TRIG_ROUND_MASK);
900 DPRINTK
901 ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
902 devpriv->i8254_osc_base, divisor1, divisor2,
903 devpriv->ai_timer1);
904 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
905 if (mode != 2) {
906 /* start pacer */
907 start_pacer(dev, mode, divisor1, divisor2);
908 } else {
909 devpriv->ai_et_div1 = divisor1;
910 devpriv->ai_et_div2 = divisor2;
912 break;
913 case 3:
914 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
915 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
916 break;
919 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
920 return 0;
923 #ifdef PCI171X_EXTDEBUG
925 ==============================================================================
927 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
929 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
930 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
931 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
932 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
933 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
934 cmd->scan_end_src);
935 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
936 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
938 #endif
941 ==============================================================================
943 static int pci171x_ai_cmdtest(struct comedi_device *dev,
944 struct comedi_subdevice *s,
945 struct comedi_cmd *cmd)
947 int err = 0;
948 int tmp;
949 unsigned int divisor1 = 0, divisor2 = 0;
951 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
952 #ifdef PCI171X_EXTDEBUG
953 pci171x_cmdtest_out(-1, cmd);
954 #endif
955 /* step 1: make sure trigger sources are trivially valid */
957 tmp = cmd->start_src;
958 cmd->start_src &= TRIG_NOW | TRIG_EXT;
959 if (!cmd->start_src || tmp != cmd->start_src)
960 err++;
962 tmp = cmd->scan_begin_src;
963 cmd->scan_begin_src &= TRIG_FOLLOW;
964 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
965 err++;
967 tmp = cmd->convert_src;
968 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
969 if (!cmd->convert_src || tmp != cmd->convert_src)
970 err++;
972 tmp = cmd->scan_end_src;
973 cmd->scan_end_src &= TRIG_COUNT;
974 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
975 err++;
977 tmp = cmd->stop_src;
978 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
979 if (!cmd->stop_src || tmp != cmd->stop_src)
980 err++;
982 if (err) {
983 #ifdef PCI171X_EXTDEBUG
984 pci171x_cmdtest_out(1, cmd);
985 #endif
986 DPRINTK
987 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
988 err);
989 return 1;
992 /* step 2: make sure trigger sources are unique and mutually compatible */
994 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
995 cmd->start_src = TRIG_NOW;
996 err++;
999 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1000 cmd->scan_begin_src = TRIG_FOLLOW;
1001 err++;
1004 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1005 err++;
1007 if (cmd->scan_end_src != TRIG_COUNT) {
1008 cmd->scan_end_src = TRIG_COUNT;
1009 err++;
1012 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1013 err++;
1015 if (err) {
1016 #ifdef PCI171X_EXTDEBUG
1017 pci171x_cmdtest_out(2, cmd);
1018 #endif
1019 DPRINTK
1020 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1021 err);
1022 return 2;
1025 /* step 3: make sure arguments are trivially compatible */
1027 if (cmd->start_arg != 0) {
1028 cmd->start_arg = 0;
1029 err++;
1032 if (cmd->scan_begin_arg != 0) {
1033 cmd->scan_begin_arg = 0;
1034 err++;
1037 if (cmd->convert_src == TRIG_TIMER) {
1038 if (cmd->convert_arg < this_board->ai_ns_min) {
1039 cmd->convert_arg = this_board->ai_ns_min;
1040 err++;
1042 } else { /* TRIG_FOLLOW */
1043 if (cmd->convert_arg != 0) {
1044 cmd->convert_arg = 0;
1045 err++;
1049 if (cmd->scan_end_arg != cmd->chanlist_len) {
1050 cmd->scan_end_arg = cmd->chanlist_len;
1051 err++;
1053 if (cmd->stop_src == TRIG_COUNT) {
1054 if (!cmd->stop_arg) {
1055 cmd->stop_arg = 1;
1056 err++;
1058 } else { /* TRIG_NONE */
1059 if (cmd->stop_arg != 0) {
1060 cmd->stop_arg = 0;
1061 err++;
1065 if (err) {
1066 #ifdef PCI171X_EXTDEBUG
1067 pci171x_cmdtest_out(3, cmd);
1068 #endif
1069 DPRINTK
1070 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1071 err);
1072 return 3;
1075 /* step 4: fix up any arguments */
1077 if (cmd->convert_src == TRIG_TIMER) {
1078 tmp = cmd->convert_arg;
1079 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1080 &divisor2, &cmd->convert_arg,
1081 cmd->flags & TRIG_ROUND_MASK);
1082 if (cmd->convert_arg < this_board->ai_ns_min)
1083 cmd->convert_arg = this_board->ai_ns_min;
1084 if (tmp != cmd->convert_arg)
1085 err++;
1088 if (err) {
1089 DPRINTK
1090 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1091 err);
1092 return 4;
1095 /* step 5: complain about special chanlist considerations */
1097 if (cmd->chanlist) {
1098 if (!check_channel_list(dev, s, cmd->chanlist,
1099 cmd->chanlist_len))
1100 return 5; /* incorrect channels list */
1103 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1104 return 0;
1108 ==============================================================================
1110 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1112 struct comedi_cmd *cmd = &s->async->cmd;
1114 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1115 devpriv->ai_n_chan = cmd->chanlist_len;
1116 devpriv->ai_chanlist = cmd->chanlist;
1117 devpriv->ai_flags = cmd->flags;
1118 devpriv->ai_data_len = s->async->prealloc_bufsz;
1119 devpriv->ai_data = s->async->prealloc_buf;
1120 devpriv->ai_timer1 = 0;
1121 devpriv->ai_timer2 = 0;
1123 if (cmd->stop_src == TRIG_COUNT)
1124 devpriv->ai_scans = cmd->stop_arg;
1125 else
1126 devpriv->ai_scans = 0;
1129 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1130 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1131 devpriv->ai_timer1 = cmd->convert_arg;
1132 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1133 TRIG_EXT ? 2 : 1, dev,
1136 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1137 return pci171x_ai_docmd_and_mode(3, dev, s);
1141 return -1;
1145 ==============================================================================
1146 Check if channel list from user is builded correctly
1147 If it's ok, then program scan/gain logic.
1148 This works for all cards.
1150 static int check_channel_list(struct comedi_device *dev,
1151 struct comedi_subdevice *s,
1152 unsigned int *chanlist, unsigned int n_chan)
1154 unsigned int chansegment[32];
1155 unsigned int i, nowmustbechan, seglen, segpos;
1157 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan);
1158 /* correct channel and range number check itself comedi/range.c */
1159 if (n_chan < 1) {
1160 comedi_error(dev, "range/channel list is empty!");
1161 return 0;
1164 if (n_chan > 1) {
1165 chansegment[0] = chanlist[0]; /* first channel is everytime ok */
1166 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */
1167 /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1168 if (chanlist[0] == chanlist[i])
1169 break; /* we detect loop, this must by finish */
1170 if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */
1171 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1172 comedi_error(dev,
1173 "Odd channel can't be differential input!\n");
1174 return 0;
1176 nowmustbechan =
1177 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1178 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1179 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1180 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */
1181 printk
1182 ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1183 i, CR_CHAN(chanlist[i]), nowmustbechan,
1184 CR_CHAN(chanlist[0]));
1185 return 0;
1187 chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
1190 for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */
1191 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
1192 if (chanlist[i] != chansegment[i % seglen]) {
1193 printk
1194 ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1195 i, CR_CHAN(chansegment[i]),
1196 CR_RANGE(chansegment[i]),
1197 CR_AREF(chansegment[i]),
1198 CR_CHAN(chanlist[i % seglen]),
1199 CR_RANGE(chanlist[i % seglen]),
1200 CR_AREF(chansegment[i % seglen]));
1201 return 0; /* chan/gain list is strange */
1204 } else {
1205 seglen = 1;
1207 return seglen;
1210 static void setup_channel_list(struct comedi_device *dev,
1211 struct comedi_subdevice *s,
1212 unsigned int *chanlist, unsigned int n_chan,
1213 unsigned int seglen)
1215 unsigned int i, range, chanprog;
1217 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan,
1218 seglen);
1219 devpriv->act_chanlist_len = seglen;
1220 devpriv->act_chanlist_pos = 0;
1222 DPRINTK("SegLen: %d\n", seglen);
1223 for (i = 0; i < seglen; i++) { /* store range list to card */
1224 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1225 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
1226 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1227 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1228 range |= 0x0020;
1229 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
1230 #ifdef PCI171x_PARANOIDCHECK
1231 devpriv->act_chanlist[i] =
1232 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1233 #endif
1234 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1235 devpriv->act_chanlist[i]);
1237 #ifdef PCI171x_PARANOIDCHECK
1238 for ( ; i < n_chan; i++) { /* store remainder of channel list */
1239 devpriv->act_chanlist[i] =
1240 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1242 #endif
1244 devpriv->ai_et_MuxVal =
1245 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1246 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
1247 DPRINTK("MUX: %4x L%4x.H%4x\n",
1248 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1249 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1253 ==============================================================================
1255 static void start_pacer(struct comedi_device *dev, int mode,
1256 unsigned int divisor1, unsigned int divisor2)
1258 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1259 divisor1, divisor2);
1260 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1261 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1263 if (mode == 1) {
1264 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1265 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1266 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1267 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1269 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1273 ==============================================================================
1275 static int pci171x_ai_cancel(struct comedi_device *dev,
1276 struct comedi_subdevice *s)
1278 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1280 switch (this_board->cardtype) {
1281 default:
1282 devpriv->CntrlReg &= Control_CNT0;
1283 devpriv->CntrlReg |= Control_SW;
1285 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1286 start_pacer(dev, -1, 0, 0);
1287 outb(0, dev->iobase + PCI171x_CLRFIFO);
1288 outb(0, dev->iobase + PCI171x_CLRINT);
1289 break;
1292 devpriv->ai_do = 0;
1293 devpriv->ai_act_scan = 0;
1294 s->async->cur_chan = 0;
1295 devpriv->ai_buf_ptr = 0;
1296 devpriv->neverending_ai = 0;
1298 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1299 return 0;
1303 ==============================================================================
1305 static int pci171x_reset(struct comedi_device *dev)
1307 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1308 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1309 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1310 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1311 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1312 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1313 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1314 devpriv->da_ranges = 0;
1315 if (this_board->n_aochan) {
1316 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1317 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1318 devpriv->ao_data[0] = 0x0000;
1319 if (this_board->n_aochan > 1) {
1320 outw(0, dev->iobase + PCI171x_DA2);
1321 devpriv->ao_data[1] = 0x0000;
1324 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1325 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1326 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1328 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1329 return 0;
1333 ==============================================================================
1335 static int pci1720_reset(struct comedi_device *dev)
1337 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1338 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1339 devpriv->da_ranges = 0xAA;
1340 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1341 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1342 outw(0x0800, dev->iobase + PCI1720_DA1);
1343 outw(0x0800, dev->iobase + PCI1720_DA2);
1344 outw(0x0800, dev->iobase + PCI1720_DA3);
1345 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1346 devpriv->ao_data[0] = 0x0800;
1347 devpriv->ao_data[1] = 0x0800;
1348 devpriv->ao_data[2] = 0x0800;
1349 devpriv->ao_data[3] = 0x0800;
1350 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1351 return 0;
1355 ==============================================================================
1357 static int pci1710_reset(struct comedi_device *dev)
1359 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1360 switch (this_board->cardtype) {
1361 case TYPE_PCI1720:
1362 return pci1720_reset(dev);
1363 default:
1364 return pci171x_reset(dev);
1366 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1370 ==============================================================================
1372 static int pci1710_attach(struct comedi_device *dev,
1373 struct comedi_devconfig *it)
1375 struct comedi_subdevice *s;
1376 int ret, subdev, n_subdevices;
1377 unsigned int irq;
1378 unsigned long iobase;
1379 struct pci_dev *pcidev;
1380 int opt_bus, opt_slot;
1381 const char *errstr;
1382 unsigned char pci_bus, pci_slot, pci_func;
1383 int i;
1384 int board_index;
1386 printk("comedi%d: adv_pci1710: ", dev->minor);
1388 opt_bus = it->options[0];
1389 opt_slot = it->options[1];
1391 ret = alloc_private(dev, sizeof(struct pci1710_private));
1392 if (ret < 0) {
1393 printk(" - Allocation failed!\n");
1394 return -ENOMEM;
1397 /* Look for matching PCI device */
1398 errstr = "not found!";
1399 pcidev = NULL;
1400 board_index = this_board - boardtypes;
1401 while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
1402 PCI_ANY_ID, pcidev))) {
1403 if (strcmp(this_board->name, DRV_NAME) == 0) {
1404 for (i = 0; i < n_boardtypes; ++i) {
1405 if (pcidev->device == boardtypes[i].device_id) {
1406 board_index = i;
1407 break;
1410 if (i == n_boardtypes)
1411 continue;
1412 } else {
1413 if (pcidev->device != boardtypes[board_index].device_id)
1414 continue;
1417 /* Found matching vendor/device. */
1418 if (opt_bus || opt_slot) {
1419 /* Check bus/slot. */
1420 if (opt_bus != pcidev->bus->number
1421 || opt_slot != PCI_SLOT(pcidev->devfn))
1422 continue; /* no match */
1425 * Look for device that isn't in use.
1426 * Enable PCI device and request regions.
1428 if (comedi_pci_enable(pcidev, DRV_NAME)) {
1429 errstr =
1430 "failed to enable PCI device and request regions!";
1431 continue;
1433 /* fixup board_ptr in case we were using the dummy entry with the driver name */
1434 dev->board_ptr = &boardtypes[board_index];
1435 break;
1438 if (!pcidev) {
1439 if (opt_bus || opt_slot) {
1440 printk(" - Card at b:s %d:%d %s\n",
1441 opt_bus, opt_slot, errstr);
1442 } else {
1443 printk(" - Card %s\n", errstr);
1445 return -EIO;
1448 pci_bus = pcidev->bus->number;
1449 pci_slot = PCI_SLOT(pcidev->devfn);
1450 pci_func = PCI_FUNC(pcidev->devfn);
1451 irq = pcidev->irq;
1452 iobase = pci_resource_start(pcidev, 2);
1454 printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
1455 iobase);
1457 dev->iobase = iobase;
1459 dev->board_name = this_board->name;
1460 devpriv->pcidev = pcidev;
1462 n_subdevices = 0;
1463 if (this_board->n_aichan)
1464 n_subdevices++;
1465 if (this_board->n_aochan)
1466 n_subdevices++;
1467 if (this_board->n_dichan)
1468 n_subdevices++;
1469 if (this_board->n_dochan)
1470 n_subdevices++;
1471 if (this_board->n_counter)
1472 n_subdevices++;
1474 ret = alloc_subdevices(dev, n_subdevices);
1475 if (ret < 0) {
1476 printk(" - Allocation failed!\n");
1477 return ret;
1480 pci1710_reset(dev);
1482 if (this_board->have_irq) {
1483 if (irq) {
1484 if (request_irq(irq, interrupt_service_pci1710,
1485 IRQF_SHARED, "Advantech PCI-1710",
1486 dev)) {
1487 printk
1488 (", unable to allocate IRQ %d, DISABLING IT",
1489 irq);
1490 irq = 0; /* Can't use IRQ */
1491 } else {
1492 printk(", irq=%u", irq);
1494 } else {
1495 printk(", IRQ disabled");
1497 } else {
1498 irq = 0;
1501 dev->irq = irq;
1503 printk(".\n");
1505 subdev = 0;
1507 if (this_board->n_aichan) {
1508 s = dev->subdevices + subdev;
1509 dev->read_subdev = s;
1510 s->type = COMEDI_SUBD_AI;
1511 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1512 if (this_board->n_aichand)
1513 s->subdev_flags |= SDF_DIFF;
1514 s->n_chan = this_board->n_aichan;
1515 s->maxdata = this_board->ai_maxdata;
1516 s->len_chanlist = this_board->n_aichan;
1517 s->range_table = this_board->rangelist_ai;
1518 s->cancel = pci171x_ai_cancel;
1519 s->insn_read = pci171x_insn_read_ai;
1520 if (irq) {
1521 s->subdev_flags |= SDF_CMD_READ;
1522 s->do_cmdtest = pci171x_ai_cmdtest;
1523 s->do_cmd = pci171x_ai_cmd;
1525 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
1526 subdev++;
1529 if (this_board->n_aochan) {
1530 s = dev->subdevices + subdev;
1531 s->type = COMEDI_SUBD_AO;
1532 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1533 s->n_chan = this_board->n_aochan;
1534 s->maxdata = this_board->ao_maxdata;
1535 s->len_chanlist = this_board->n_aochan;
1536 s->range_table = this_board->rangelist_ao;
1537 switch (this_board->cardtype) {
1538 case TYPE_PCI1720:
1539 s->insn_write = pci1720_insn_write_ao;
1540 break;
1541 default:
1542 s->insn_write = pci171x_insn_write_ao;
1543 break;
1545 s->insn_read = pci171x_insn_read_ao;
1546 subdev++;
1549 if (this_board->n_dichan) {
1550 s = dev->subdevices + subdev;
1551 s->type = COMEDI_SUBD_DI;
1552 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1553 s->n_chan = this_board->n_dichan;
1554 s->maxdata = 1;
1555 s->len_chanlist = this_board->n_dichan;
1556 s->range_table = &range_digital;
1557 s->io_bits = 0; /* all bits input */
1558 s->insn_bits = pci171x_insn_bits_di;
1559 subdev++;
1562 if (this_board->n_dochan) {
1563 s = dev->subdevices + subdev;
1564 s->type = COMEDI_SUBD_DO;
1565 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1566 s->n_chan = this_board->n_dochan;
1567 s->maxdata = 1;
1568 s->len_chanlist = this_board->n_dochan;
1569 s->range_table = &range_digital;
1570 /* all bits output */
1571 s->io_bits = (1 << this_board->n_dochan) - 1;
1572 s->state = 0;
1573 s->insn_bits = pci171x_insn_bits_do;
1574 subdev++;
1577 if (this_board->n_counter) {
1578 s = dev->subdevices + subdev;
1579 s->type = COMEDI_SUBD_COUNTER;
1580 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1581 s->n_chan = this_board->n_counter;
1582 s->len_chanlist = this_board->n_counter;
1583 s->maxdata = 0xffff;
1584 s->range_table = &range_unknown;
1585 s->insn_read = pci171x_insn_counter_read;
1586 s->insn_write = pci171x_insn_counter_write;
1587 s->insn_config = pci171x_insn_counter_config;
1588 subdev++;
1591 devpriv->valid = 1;
1593 return 0;
1597 ==============================================================================
1599 static int pci1710_detach(struct comedi_device *dev)
1602 if (dev->private) {
1603 if (devpriv->valid)
1604 pci1710_reset(dev);
1605 if (dev->irq)
1606 free_irq(dev->irq, dev);
1607 if (devpriv->pcidev) {
1608 if (dev->iobase)
1609 comedi_pci_disable(devpriv->pcidev);
1611 pci_dev_put(devpriv->pcidev);
1615 return 0;
1619 ==============================================================================
1621 static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
1622 const struct pci_device_id *ent)
1624 return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
1627 static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
1629 comedi_pci_auto_unconfig(dev);
1632 static struct pci_driver driver_pci1710_pci_driver = {
1633 .id_table = pci1710_pci_table,
1634 .probe = &driver_pci1710_pci_probe,
1635 .remove = __devexit_p(&driver_pci1710_pci_remove)
1638 static int __init driver_pci1710_init_module(void)
1640 int retval;
1642 retval = comedi_driver_register(&driver_pci1710);
1643 if (retval < 0)
1644 return retval;
1646 driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
1647 return pci_register_driver(&driver_pci1710_pci_driver);
1650 static void __exit driver_pci1710_cleanup_module(void)
1652 pci_unregister_driver(&driver_pci1710_pci_driver);
1653 comedi_driver_unregister(&driver_pci1710);
1656 module_init(driver_pci1710_init_module);
1657 module_exit(driver_pci1710_cleanup_module);
1659 ==============================================================================
1662 MODULE_AUTHOR("Comedi http://www.comedi.org");
1663 MODULE_DESCRIPTION("Comedi low-level driver");
1664 MODULE_LICENSE("GPL");