Merge branches 'atags', 'cache-l2x0', 'clkdev', 'fixes', 'integrator', 'misc', 'opcod...
[deliverable/linux.git] / drivers / staging / comedi / drivers / adv_pci1710.c
1 /*
2 * comedi/drivers/adv_pci1710.c
3 *
4 * Author: Michal Dobes <dobes@tesnet.cz>
5 *
6 * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7 * for testing and informations.
8 *
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
12 *
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
17 *
18 */
19 /*
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
28
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.
32
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.
36
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.
42 */
43
44 #include <linux/interrupt.h>
45
46 #include "../comedidev.h"
47
48 #include "8253.h"
49 #include "amcc_s5933.h"
50
51 #define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
52 * correct channel number on every 12 bit
53 * sample */
54
55 #undef PCI171X_EXTDEBUG
56
57 #define DRV_NAME "adv_pci1710"
58
59 #undef DPRINTK
60 #ifdef PCI171X_EXTDEBUG
61 #define DPRINTK(fmt, args...) printk(fmt, ## args)
62 #else
63 #define DPRINTK(fmt, args...)
64 #endif
65
66 #define PCI_VENDOR_ID_ADVANTECH 0x13fe
67
68 /* hardware types of the cards */
69 #define TYPE_PCI171X 0
70 #define TYPE_PCI1713 2
71 #define TYPE_PCI1720 3
72
73 #define IORANGE_171x 32
74 #define IORANGE_1720 16
75
76 #define PCI171x_AD_DATA 0 /* R: A/D data */
77 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
78 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
79 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
80 #define PCI171x_STATUS 6 /* R: status register */
81 #define PCI171x_CONTROL 6 /* W: control register */
82 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
83 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
84 #define PCI171x_DA1 10 /* W: D/A register */
85 #define PCI171x_DA2 12 /* W: D/A register */
86 #define PCI171x_DAREF 14 /* W: D/A reference control */
87 #define PCI171x_DI 16 /* R: digi inputs */
88 #define PCI171x_DO 16 /* R: digi inputs */
89 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
90 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
91 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
92 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
93
94 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
95 * reg) */
96 #define Status_FE 0x0100 /* 1=FIFO is empty */
97 #define Status_FH 0x0200 /* 1=FIFO is half full */
98 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
99 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
100 /* bits from control register (PCI171x_CONTROL) */
101 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
102 * 0=have internal 100kHz source */
103 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
104 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
105 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
106 #define Control_EXT 0x0004 /* 1=external trigger source */
107 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
108 #define Control_SW 0x0001 /* 1=enable software trigger source */
109 /* bits from counter control register (PCI171x_CNTCTRL) */
110 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
111 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
112 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
113 #define Counter_M2 0x0008
114 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
115 #define Counter_RW1 0x0020
116 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
117 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
118 * 11 for read-back command */
119
120 #define PCI1720_DA0 0 /* W: D/A register 0 */
121 #define PCI1720_DA1 2 /* W: D/A register 1 */
122 #define PCI1720_DA2 4 /* W: D/A register 2 */
123 #define PCI1720_DA3 6 /* W: D/A register 3 */
124 #define PCI1720_RANGE 8 /* R/W: D/A range register */
125 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
126 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
127
128 /* D/A synchronized control (PCI1720_SYNCONT) */
129 #define Syncont_SC0 1 /* set synchronous output mode */
130
131 static const struct comedi_lrange range_pci1710_3 = { 9, {
132 BIP_RANGE(5),
133 BIP_RANGE(2.5),
134 BIP_RANGE(1.25),
135 BIP_RANGE(0.625),
136 BIP_RANGE(10),
137 UNI_RANGE(10),
138 UNI_RANGE(5),
139 UNI_RANGE(2.5),
140 UNI_RANGE(1.25)
141 }
142 };
143
144 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
145 0x10, 0x11, 0x12, 0x13 };
146
147 static const struct comedi_lrange range_pci1710hg = { 12, {
148 BIP_RANGE(5),
149 BIP_RANGE(0.5),
150 BIP_RANGE(0.05),
151 BIP_RANGE(0.005),
152 BIP_RANGE(10),
153 BIP_RANGE(1),
154 BIP_RANGE(0.1),
155 BIP_RANGE(0.01),
156 UNI_RANGE(10),
157 UNI_RANGE(1),
158 UNI_RANGE(0.1),
159 UNI_RANGE(0.01)
160 }
161 };
162
163 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
164 0x05, 0x06, 0x07, 0x10, 0x11,
165 0x12, 0x13 };
166
167 static const struct comedi_lrange range_pci17x1 = { 5, {
168 BIP_RANGE(10),
169 BIP_RANGE(5),
170 BIP_RANGE(2.5),
171 BIP_RANGE(1.25),
172 BIP_RANGE(0.625)
173 }
174 };
175
176 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
177
178 static const struct comedi_lrange range_pci1720 = { 4, {
179 UNI_RANGE(5),
180 UNI_RANGE(10),
181 BIP_RANGE(5),
182 BIP_RANGE(10)
183 }
184 };
185
186 static const struct comedi_lrange range_pci171x_da = { 2, {
187 UNI_RANGE(5),
188 UNI_RANGE(10),
189 }
190 };
191
192 struct boardtype {
193 const char *name; /* board name */
194 int device_id;
195 int iorange; /* I/O range len */
196 char have_irq; /* 1=card support IRQ */
197 char cardtype; /* 0=1710& co. 2=1713, ... */
198 int n_aichan; /* num of A/D chans */
199 int n_aichand; /* num of A/D chans in diff mode */
200 int n_aochan; /* num of D/A chans */
201 int n_dichan; /* num of DI chans */
202 int n_dochan; /* num of DO chans */
203 int n_counter; /* num of counters */
204 int ai_maxdata; /* resolution of A/D */
205 int ao_maxdata; /* resolution of D/A */
206 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
207 const char *rangecode_ai; /* range codes for programming */
208 const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
209 unsigned int ai_ns_min; /* max sample speed of card v ns */
210 unsigned int fifo_half_size; /* size of FIFO/2 */
211 };
212
213 static const struct boardtype boardtypes[] = {
214 {"pci1710", 0x1710,
215 IORANGE_171x, 1, TYPE_PCI171X,
216 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
217 &range_pci1710_3, range_codes_pci1710_3,
218 &range_pci171x_da,
219 10000, 2048},
220 {"pci1710hg", 0x1710,
221 IORANGE_171x, 1, TYPE_PCI171X,
222 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff,
223 &range_pci1710hg, range_codes_pci1710hg,
224 &range_pci171x_da,
225 10000, 2048},
226 {"pci1711", 0x1711,
227 IORANGE_171x, 1, TYPE_PCI171X,
228 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff,
229 &range_pci17x1, range_codes_pci17x1, &range_pci171x_da,
230 10000, 512},
231 {"pci1713", 0x1713,
232 IORANGE_171x, 1, TYPE_PCI1713,
233 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000,
234 &range_pci1710_3, range_codes_pci1710_3, NULL,
235 10000, 2048},
236 {"pci1720", 0x1720,
237 IORANGE_1720, 0, TYPE_PCI1720,
238 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
239 NULL, NULL, &range_pci1720,
240 0, 0},
241 {"pci1731", 0x1731,
242 IORANGE_171x, 1, TYPE_PCI171X,
243 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000,
244 &range_pci17x1, range_codes_pci17x1, NULL,
245 10000, 512},
246 /* dummy entry corresponding to driver name */
247 {.name = DRV_NAME},
248 };
249
250 struct pci1710_private {
251 char valid; /* card is usable */
252 char neverending_ai; /* we do unlimited AI */
253 unsigned int CntrlReg; /* Control register */
254 unsigned int i8254_osc_base; /* frequence of onboard oscilator */
255 unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
256 unsigned int ai_act_scan; /* how many scans we finished */
257 unsigned int ai_act_chan; /* actual position in actual scan */
258 unsigned int ai_buf_ptr; /* data buffer ptr in samples */
259 unsigned char ai_eos; /* 1=EOS wake up */
260 unsigned char ai_et;
261 unsigned int ai_et_CntrlReg;
262 unsigned int ai_et_MuxVal;
263 unsigned int ai_et_div1, ai_et_div2;
264 unsigned int act_chanlist[32]; /* list of scaned channel */
265 unsigned char act_chanlist_len; /* len of scanlist */
266 unsigned char act_chanlist_pos; /* actual position in MUX list */
267 unsigned char da_ranges; /* copy of D/A outpit range register */
268 unsigned int ai_scans; /* len of scanlist */
269 unsigned int ai_n_chan; /* how many channels is measured */
270 unsigned int *ai_chanlist; /* actaul chanlist */
271 unsigned int ai_flags; /* flaglist */
272 unsigned int ai_data_len; /* len of data buffer */
273 short *ai_data; /* data buffer */
274 unsigned int ai_timer1; /* timers */
275 unsigned int ai_timer2;
276 short ao_data[4]; /* data output buffer */
277 unsigned int cnt0_write_wait; /* after a write, wait for update of the
278 * internal state */
279 };
280
281 #define devpriv ((struct pci1710_private *)dev->private)
282 #define this_board ((const struct boardtype *)dev->board_ptr)
283
284 /*
285 ==============================================================================
286 */
287
288 static int check_channel_list(struct comedi_device *dev,
289 struct comedi_subdevice *s,
290 unsigned int *chanlist, unsigned int n_chan);
291 static void setup_channel_list(struct comedi_device *dev,
292 struct comedi_subdevice *s,
293 unsigned int *chanlist, unsigned int n_chan,
294 unsigned int seglen);
295 static void start_pacer(struct comedi_device *dev, int mode,
296 unsigned int divisor1, unsigned int divisor2);
297 static int pci1710_reset(struct comedi_device *dev);
298 static int pci171x_ai_cancel(struct comedi_device *dev,
299 struct comedi_subdevice *s);
300
301 /* used for gain list programming */
302 static const unsigned int muxonechan[] = {
303 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
304 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
305 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
306 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
307 };
308
309 /*
310 ==============================================================================
311 */
312 static int pci171x_insn_read_ai(struct comedi_device *dev,
313 struct comedi_subdevice *s,
314 struct comedi_insn *insn, unsigned int *data)
315 {
316 int n, timeout;
317 #ifdef PCI171x_PARANOIDCHECK
318 unsigned int idata;
319 #endif
320
321 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n");
322 devpriv->CntrlReg &= Control_CNT0;
323 devpriv->CntrlReg |= Control_SW; /* set software trigger */
324 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
325 outb(0, dev->iobase + PCI171x_CLRFIFO);
326 outb(0, dev->iobase + PCI171x_CLRINT);
327
328 setup_channel_list(dev, s, &insn->chanspec, 1, 1);
329
330 DPRINTK("adv_pci1710 A ST=%4x IO=%x\n",
331 inw(dev->iobase + PCI171x_STATUS),
332 dev->iobase + PCI171x_STATUS);
333 for (n = 0; n < insn->n; n++) {
334 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
335 DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n,
336 inw(dev->iobase + PCI171x_STATUS));
337 /* udelay(1); */
338 DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n,
339 inw(dev->iobase + PCI171x_STATUS));
340 timeout = 100;
341 while (timeout--) {
342 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
343 goto conv_finish;
344 if (!(timeout % 10))
345 DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n,
346 timeout,
347 inw(dev->iobase + PCI171x_STATUS));
348 }
349 comedi_error(dev, "A/D insn timeout");
350 outb(0, dev->iobase + PCI171x_CLRFIFO);
351 outb(0, dev->iobase + PCI171x_CLRINT);
352 data[n] = 0;
353 DPRINTK
354 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
355 n);
356 return -ETIME;
357
358 conv_finish:
359 #ifdef PCI171x_PARANOIDCHECK
360 idata = inw(dev->iobase + PCI171x_AD_DATA);
361 if (this_board->cardtype != TYPE_PCI1713)
362 if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
363 comedi_error(dev, "A/D insn data droput!");
364 return -ETIME;
365 }
366 data[n] = idata & 0x0fff;
367 #else
368 data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
369 #endif
370
371 }
372
373 outb(0, dev->iobase + PCI171x_CLRFIFO);
374 outb(0, dev->iobase + PCI171x_CLRINT);
375
376 DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n);
377 return n;
378 }
379
380 /*
381 ==============================================================================
382 */
383 static int pci171x_insn_write_ao(struct comedi_device *dev,
384 struct comedi_subdevice *s,
385 struct comedi_insn *insn, unsigned int *data)
386 {
387 int n, chan, range, ofs;
388
389 chan = CR_CHAN(insn->chanspec);
390 range = CR_RANGE(insn->chanspec);
391 if (chan) {
392 devpriv->da_ranges &= 0xfb;
393 devpriv->da_ranges |= (range << 2);
394 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
395 ofs = PCI171x_DA2;
396 } else {
397 devpriv->da_ranges &= 0xfe;
398 devpriv->da_ranges |= range;
399 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
400 ofs = PCI171x_DA1;
401 }
402
403 for (n = 0; n < insn->n; n++)
404 outw(data[n], dev->iobase + ofs);
405
406 devpriv->ao_data[chan] = data[n];
407
408 return n;
409
410 }
411
412 /*
413 ==============================================================================
414 */
415 static int pci171x_insn_read_ao(struct comedi_device *dev,
416 struct comedi_subdevice *s,
417 struct comedi_insn *insn, unsigned int *data)
418 {
419 int n, chan;
420
421 chan = CR_CHAN(insn->chanspec);
422 for (n = 0; n < insn->n; n++)
423 data[n] = devpriv->ao_data[chan];
424
425 return n;
426 }
427
428 /*
429 ==============================================================================
430 */
431 static int pci171x_insn_bits_di(struct comedi_device *dev,
432 struct comedi_subdevice *s,
433 struct comedi_insn *insn, unsigned int *data)
434 {
435 data[1] = inw(dev->iobase + PCI171x_DI);
436
437 return insn->n;
438 }
439
440 /*
441 ==============================================================================
442 */
443 static int pci171x_insn_bits_do(struct comedi_device *dev,
444 struct comedi_subdevice *s,
445 struct comedi_insn *insn, unsigned int *data)
446 {
447 if (data[0]) {
448 s->state &= ~data[0];
449 s->state |= (data[0] & data[1]);
450 outw(s->state, dev->iobase + PCI171x_DO);
451 }
452 data[1] = s->state;
453
454 return insn->n;
455 }
456
457 /*
458 ==============================================================================
459 */
460 static int pci171x_insn_counter_read(struct comedi_device *dev,
461 struct comedi_subdevice *s,
462 struct comedi_insn *insn,
463 unsigned int *data)
464 {
465 unsigned int msb, lsb, ccntrl;
466 int i;
467
468 ccntrl = 0xD2; /* count only */
469 for (i = 0; i < insn->n; i++) {
470 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
471
472 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
473 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
474
475 data[0] = lsb | (msb << 8);
476 }
477
478 return insn->n;
479 }
480
481 /*
482 ==============================================================================
483 */
484 static int pci171x_insn_counter_write(struct comedi_device *dev,
485 struct comedi_subdevice *s,
486 struct comedi_insn *insn,
487 unsigned int *data)
488 {
489 uint msb, lsb, ccntrl, status;
490
491 lsb = data[0] & 0x00FF;
492 msb = (data[0] & 0xFF00) >> 8;
493
494 /* write lsb, then msb */
495 outw(lsb, dev->iobase + PCI171x_CNT0);
496 outw(msb, dev->iobase + PCI171x_CNT0);
497
498 if (devpriv->cnt0_write_wait) {
499 /* wait for the new count to be loaded */
500 ccntrl = 0xE2;
501 do {
502 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
503 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
504 } while (status & 0x40);
505 }
506
507 return insn->n;
508 }
509
510 /*
511 ==============================================================================
512 */
513 static int pci171x_insn_counter_config(struct comedi_device *dev,
514 struct comedi_subdevice *s,
515 struct comedi_insn *insn,
516 unsigned int *data)
517 {
518 #ifdef unused
519 /* This doesn't work like a normal Comedi counter config */
520 uint ccntrl = 0;
521
522 devpriv->cnt0_write_wait = data[0] & 0x20;
523
524 /* internal or external clock? */
525 if (!(data[0] & 0x10)) { /* internal */
526 devpriv->CntrlReg &= ~Control_CNT0;
527 } else {
528 devpriv->CntrlReg |= Control_CNT0;
529 }
530 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
531
532 if (data[0] & 0x01)
533 ccntrl |= Counter_M0;
534 if (data[0] & 0x02)
535 ccntrl |= Counter_M1;
536 if (data[0] & 0x04)
537 ccntrl |= Counter_M2;
538 if (data[0] & 0x08)
539 ccntrl |= Counter_BCD;
540 ccntrl |= Counter_RW0; /* set read/write mode */
541 ccntrl |= Counter_RW1;
542 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
543 #endif
544
545 return 1;
546 }
547
548 /*
549 ==============================================================================
550 */
551 static int pci1720_insn_write_ao(struct comedi_device *dev,
552 struct comedi_subdevice *s,
553 struct comedi_insn *insn, unsigned int *data)
554 {
555 int n, rangereg, chan;
556
557 chan = CR_CHAN(insn->chanspec);
558 rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
559 rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
560 if (rangereg != devpriv->da_ranges) {
561 outb(rangereg, dev->iobase + PCI1720_RANGE);
562 devpriv->da_ranges = rangereg;
563 }
564
565 for (n = 0; n < insn->n; n++) {
566 outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
567 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
568 }
569
570 devpriv->ao_data[chan] = data[n];
571
572 return n;
573 }
574
575 /*
576 ==============================================================================
577 */
578 static void interrupt_pci1710_every_sample(void *d)
579 {
580 struct comedi_device *dev = d;
581 struct comedi_subdevice *s = dev->subdevices + 0;
582 int m;
583 #ifdef PCI171x_PARANOIDCHECK
584 short sampl;
585 #endif
586
587 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n");
588 m = inw(dev->iobase + PCI171x_STATUS);
589 if (m & Status_FE) {
590 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
591 pci171x_ai_cancel(dev, s);
592 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
593 comedi_event(dev, s);
594 return;
595 }
596 if (m & Status_FF) {
597 printk
598 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
599 dev->minor, m);
600 pci171x_ai_cancel(dev, s);
601 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
602 comedi_event(dev, s);
603 return;
604 }
605
606 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
607
608 DPRINTK("FOR ");
609 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
610 #ifdef PCI171x_PARANOIDCHECK
611 sampl = inw(dev->iobase + PCI171x_AD_DATA);
612 DPRINTK("%04x:", sampl);
613 if (this_board->cardtype != TYPE_PCI1713)
614 if ((sampl & 0xf000) !=
615 devpriv->act_chanlist[s->async->cur_chan]) {
616 printk
617 ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
618 (sampl & 0xf000) >> 12,
619 (devpriv->
620 act_chanlist[s->
621 async->cur_chan] & 0xf000) >>
622 12);
623 pci171x_ai_cancel(dev, s);
624 s->async->events |=
625 COMEDI_CB_EOA | COMEDI_CB_ERROR;
626 comedi_event(dev, s);
627 return;
628 }
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);
632 #else
633 comedi_buf_put(s->async,
634 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
635 #endif
636 ++s->async->cur_chan;
637
638 if (s->async->cur_chan >= devpriv->ai_n_chan)
639 s->async->cur_chan = 0;
640
641
642 if (s->async->cur_chan == 0) { /* one scan done */
643 devpriv->ai_act_scan++;
644 DPRINTK
645 ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n",
646 s->async->buf_int_count, s->async->buf_int_ptr,
647 s->async->buf_user_count, s->async->buf_user_ptr);
648 DPRINTK("adv_pci1710 EDBG: EOS2\n");
649 if ((!devpriv->neverending_ai) &&
650 (devpriv->ai_act_scan >= devpriv->ai_scans)) {
651 /* all data sampled */
652 pci171x_ai_cancel(dev, s);
653 s->async->events |= COMEDI_CB_EOA;
654 comedi_event(dev, s);
655 return;
656 }
657 }
658 }
659
660 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
661 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
662
663 comedi_event(dev, s);
664 }
665
666 /*
667 ==============================================================================
668 */
669 static int move_block_from_fifo(struct comedi_device *dev,
670 struct comedi_subdevice *s, int n, int turn)
671 {
672 int i, j;
673 #ifdef PCI171x_PARANOIDCHECK
674 int sampl;
675 #endif
676 DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n,
677 turn);
678 j = s->async->cur_chan;
679 for (i = 0; i < n; i++) {
680 #ifdef PCI171x_PARANOIDCHECK
681 sampl = inw(dev->iobase + PCI171x_AD_DATA);
682 if (this_board->cardtype != TYPE_PCI1713)
683 if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
684 printk
685 ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
686 dev->minor, (sampl & 0xf000) >> 12,
687 (devpriv->act_chanlist[j] & 0xf000) >> 12,
688 i, j, devpriv->ai_act_scan, n, turn,
689 sampl);
690 pci171x_ai_cancel(dev, s);
691 s->async->events |=
692 COMEDI_CB_EOA | COMEDI_CB_ERROR;
693 comedi_event(dev, s);
694 return 1;
695 }
696 comedi_buf_put(s->async, sampl & 0x0fff);
697 #else
698 comedi_buf_put(s->async,
699 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
700 #endif
701 j++;
702 if (j >= devpriv->ai_n_chan) {
703 j = 0;
704 devpriv->ai_act_scan++;
705 }
706 }
707 s->async->cur_chan = j;
708 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
709 return 0;
710 }
711
712 /*
713 ==============================================================================
714 */
715 static void interrupt_pci1710_half_fifo(void *d)
716 {
717 struct comedi_device *dev = d;
718 struct comedi_subdevice *s = dev->subdevices + 0;
719 int m, samplesinbuf;
720
721 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n");
722 m = inw(dev->iobase + PCI171x_STATUS);
723 if (!(m & Status_FH)) {
724 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
725 dev->minor, m);
726 pci171x_ai_cancel(dev, s);
727 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
728 comedi_event(dev, s);
729 return;
730 }
731 if (m & Status_FF) {
732 printk
733 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
734 dev->minor, m);
735 pci171x_ai_cancel(dev, s);
736 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
737 comedi_event(dev, s);
738 return;
739 }
740
741 samplesinbuf = this_board->fifo_half_size;
742 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
743 m = devpriv->ai_data_len / sizeof(short);
744 if (move_block_from_fifo(dev, s, m, 0))
745 return;
746 samplesinbuf -= m;
747 }
748
749 if (samplesinbuf) {
750 if (move_block_from_fifo(dev, s, samplesinbuf, 1))
751 return;
752 }
753
754 if (!devpriv->neverending_ai)
755 if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
756 sampled */
757 pci171x_ai_cancel(dev, s);
758 s->async->events |= COMEDI_CB_EOA;
759 comedi_event(dev, s);
760 return;
761 }
762 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
763 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
764
765 comedi_event(dev, s);
766 }
767
768 /*
769 ==============================================================================
770 */
771 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
772 {
773 struct comedi_device *dev = d;
774
775 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
776 irq);
777 if (!dev->attached) /* is device attached? */
778 return IRQ_NONE; /* no, exit */
779 /* is this interrupt from our board? */
780 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
781 return IRQ_NONE; /* no, exit */
782
783 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
784 inw(dev->iobase + PCI171x_STATUS));
785
786 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
787 devpriv->ai_et = 0;
788 devpriv->CntrlReg &= Control_CNT0;
789 devpriv->CntrlReg |= Control_SW; /* set software trigger */
790 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
791 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
792 outb(0, dev->iobase + PCI171x_CLRFIFO);
793 outb(0, dev->iobase + PCI171x_CLRINT);
794 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
795 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
796 /* start pacer */
797 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
798 return IRQ_HANDLED;
799 }
800 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
801 interrupt_pci1710_every_sample(d);
802 } else {
803 interrupt_pci1710_half_fifo(d);
804 }
805 DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n");
806 return IRQ_HANDLED;
807 }
808
809 /*
810 ==============================================================================
811 */
812 static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
813 struct comedi_subdevice *s)
814 {
815 unsigned int divisor1 = 0, divisor2 = 0;
816 unsigned int seglen;
817
818 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
819 mode);
820 start_pacer(dev, -1, 0, 0); /* stop pacer */
821
822 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
823 devpriv->ai_n_chan);
824 if (seglen < 1)
825 return -EINVAL;
826 setup_channel_list(dev, s, devpriv->ai_chanlist,
827 devpriv->ai_n_chan, seglen);
828
829 outb(0, dev->iobase + PCI171x_CLRFIFO);
830 outb(0, dev->iobase + PCI171x_CLRINT);
831
832 devpriv->ai_do = mode;
833
834 devpriv->ai_act_scan = 0;
835 s->async->cur_chan = 0;
836 devpriv->ai_buf_ptr = 0;
837 devpriv->neverending_ai = 0;
838
839 devpriv->CntrlReg &= Control_CNT0;
840 /* don't we want wake up every scan? devpriv->ai_eos=1; */
841 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
842 devpriv->ai_eos = 1;
843 } else {
844 devpriv->CntrlReg |= Control_ONEFH;
845 devpriv->ai_eos = 0;
846 }
847
848 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
849 devpriv->neverending_ai = 1;
850 /* well, user want neverending */
851 else
852 devpriv->neverending_ai = 0;
853
854 switch (mode) {
855 case 1:
856 case 2:
857 if (devpriv->ai_timer1 < this_board->ai_ns_min)
858 devpriv->ai_timer1 = this_board->ai_ns_min;
859 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
860 if (mode == 2) {
861 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
862 devpriv->CntrlReg &=
863 ~(Control_PACER | Control_ONEFH | Control_GATE);
864 devpriv->CntrlReg |= Control_EXT;
865 devpriv->ai_et = 1;
866 } else {
867 devpriv->ai_et = 0;
868 }
869 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
870 &divisor2, &devpriv->ai_timer1,
871 devpriv->ai_flags & TRIG_ROUND_MASK);
872 DPRINTK
873 ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n",
874 devpriv->i8254_osc_base, divisor1, divisor2,
875 devpriv->ai_timer1);
876 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
877 if (mode != 2) {
878 /* start pacer */
879 start_pacer(dev, mode, divisor1, divisor2);
880 } else {
881 devpriv->ai_et_div1 = divisor1;
882 devpriv->ai_et_div2 = divisor2;
883 }
884 break;
885 case 3:
886 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
887 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
888 break;
889 }
890
891 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n");
892 return 0;
893 }
894
895 #ifdef PCI171X_EXTDEBUG
896 /*
897 ==============================================================================
898 */
899 static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
900 {
901 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
902 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
903 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
904 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
905 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
906 cmd->scan_end_src);
907 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
908 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
909 }
910 #endif
911
912 /*
913 ==============================================================================
914 */
915 static int pci171x_ai_cmdtest(struct comedi_device *dev,
916 struct comedi_subdevice *s,
917 struct comedi_cmd *cmd)
918 {
919 int err = 0;
920 int tmp;
921 unsigned int divisor1 = 0, divisor2 = 0;
922
923 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n");
924 #ifdef PCI171X_EXTDEBUG
925 pci171x_cmdtest_out(-1, cmd);
926 #endif
927 /* step 1: make sure trigger sources are trivially valid */
928
929 tmp = cmd->start_src;
930 cmd->start_src &= TRIG_NOW | TRIG_EXT;
931 if (!cmd->start_src || tmp != cmd->start_src)
932 err++;
933
934 tmp = cmd->scan_begin_src;
935 cmd->scan_begin_src &= TRIG_FOLLOW;
936 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
937 err++;
938
939 tmp = cmd->convert_src;
940 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
941 if (!cmd->convert_src || tmp != cmd->convert_src)
942 err++;
943
944 tmp = cmd->scan_end_src;
945 cmd->scan_end_src &= TRIG_COUNT;
946 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
947 err++;
948
949 tmp = cmd->stop_src;
950 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
951 if (!cmd->stop_src || tmp != cmd->stop_src)
952 err++;
953
954 if (err) {
955 #ifdef PCI171X_EXTDEBUG
956 pci171x_cmdtest_out(1, cmd);
957 #endif
958 DPRINTK(
959 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
960 err);
961 return 1;
962 }
963
964 /* step2: make sure trigger srcs are unique and mutually compatible */
965
966 if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
967 cmd->start_src = TRIG_NOW;
968 err++;
969 }
970
971 if (cmd->scan_begin_src != TRIG_FOLLOW) {
972 cmd->scan_begin_src = TRIG_FOLLOW;
973 err++;
974 }
975
976 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
977 err++;
978
979 if (cmd->scan_end_src != TRIG_COUNT) {
980 cmd->scan_end_src = TRIG_COUNT;
981 err++;
982 }
983
984 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
985 err++;
986
987 if (err) {
988 #ifdef PCI171X_EXTDEBUG
989 pci171x_cmdtest_out(2, cmd);
990 #endif
991 DPRINTK(
992 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
993 err);
994 return 2;
995 }
996
997 /* step 3: make sure arguments are trivially compatible */
998
999 if (cmd->start_arg != 0) {
1000 cmd->start_arg = 0;
1001 err++;
1002 }
1003
1004 if (cmd->scan_begin_arg != 0) {
1005 cmd->scan_begin_arg = 0;
1006 err++;
1007 }
1008
1009 if (cmd->convert_src == TRIG_TIMER) {
1010 if (cmd->convert_arg < this_board->ai_ns_min) {
1011 cmd->convert_arg = this_board->ai_ns_min;
1012 err++;
1013 }
1014 } else { /* TRIG_FOLLOW */
1015 if (cmd->convert_arg != 0) {
1016 cmd->convert_arg = 0;
1017 err++;
1018 }
1019 }
1020
1021 if (cmd->scan_end_arg != cmd->chanlist_len) {
1022 cmd->scan_end_arg = cmd->chanlist_len;
1023 err++;
1024 }
1025 if (cmd->stop_src == TRIG_COUNT) {
1026 if (!cmd->stop_arg) {
1027 cmd->stop_arg = 1;
1028 err++;
1029 }
1030 } else { /* TRIG_NONE */
1031 if (cmd->stop_arg != 0) {
1032 cmd->stop_arg = 0;
1033 err++;
1034 }
1035 }
1036
1037 if (err) {
1038 #ifdef PCI171X_EXTDEBUG
1039 pci171x_cmdtest_out(3, cmd);
1040 #endif
1041 DPRINTK(
1042 "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1043 err);
1044 return 3;
1045 }
1046
1047 /* step 4: fix up any arguments */
1048
1049 if (cmd->convert_src == TRIG_TIMER) {
1050 tmp = cmd->convert_arg;
1051 i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1,
1052 &divisor2, &cmd->convert_arg,
1053 cmd->flags & TRIG_ROUND_MASK);
1054 if (cmd->convert_arg < this_board->ai_ns_min)
1055 cmd->convert_arg = this_board->ai_ns_min;
1056 if (tmp != cmd->convert_arg)
1057 err++;
1058 }
1059
1060 if (err) {
1061 DPRINTK
1062 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1063 err);
1064 return 4;
1065 }
1066
1067 /* step 5: complain about special chanlist considerations */
1068
1069 if (cmd->chanlist) {
1070 if (!check_channel_list(dev, s, cmd->chanlist,
1071 cmd->chanlist_len))
1072 return 5; /* incorrect channels list */
1073 }
1074
1075 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1076 return 0;
1077 }
1078
1079 /*
1080 ==============================================================================
1081 */
1082 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1083 {
1084 struct comedi_cmd *cmd = &s->async->cmd;
1085
1086 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n");
1087 devpriv->ai_n_chan = cmd->chanlist_len;
1088 devpriv->ai_chanlist = cmd->chanlist;
1089 devpriv->ai_flags = cmd->flags;
1090 devpriv->ai_data_len = s->async->prealloc_bufsz;
1091 devpriv->ai_data = s->async->prealloc_buf;
1092 devpriv->ai_timer1 = 0;
1093 devpriv->ai_timer2 = 0;
1094
1095 if (cmd->stop_src == TRIG_COUNT)
1096 devpriv->ai_scans = cmd->stop_arg;
1097 else
1098 devpriv->ai_scans = 0;
1099
1100
1101 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1102 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
1103 devpriv->ai_timer1 = cmd->convert_arg;
1104 return pci171x_ai_docmd_and_mode(cmd->start_src ==
1105 TRIG_EXT ? 2 : 1, dev,
1106 s);
1107 }
1108 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1109 return pci171x_ai_docmd_and_mode(3, dev, s);
1110 }
1111 }
1112
1113 return -1;
1114 }
1115
1116 /*
1117 ==============================================================================
1118 Check if channel list from user is builded correctly
1119 If it's ok, then program scan/gain logic.
1120 This works for all cards.
1121 */
1122 static int check_channel_list(struct comedi_device *dev,
1123 struct comedi_subdevice *s,
1124 unsigned int *chanlist, unsigned int n_chan)
1125 {
1126 unsigned int chansegment[32];
1127 unsigned int i, nowmustbechan, seglen, segpos;
1128
1129 DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan);
1130 /* correct channel and range number check itself comedi/range.c */
1131 if (n_chan < 1) {
1132 comedi_error(dev, "range/channel list is empty!");
1133 return 0;
1134 }
1135
1136 if (n_chan == 1)
1137 return 1; /* seglen=1 */
1138
1139 chansegment[0] = chanlist[0]; /* first channel is every time ok */
1140 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1141 if (chanlist[0] == chanlist[i])
1142 break; /* we detected a loop, stop */
1143 if ((CR_CHAN(chanlist[i]) & 1) &&
1144 (CR_AREF(chanlist[i]) == AREF_DIFF)) {
1145 comedi_error(dev, "Odd channel cannot be differential input!\n");
1146 return 0;
1147 }
1148 nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1149 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1150 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
1151 if (nowmustbechan != CR_CHAN(chanlist[i])) {
1152 printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1153 i, CR_CHAN(chanlist[i]), nowmustbechan,
1154 CR_CHAN(chanlist[0]));
1155 return 0;
1156 }
1157 chansegment[i] = chanlist[i]; /* next correct channel in list */
1158 }
1159
1160 for (i = 0, segpos = 0; i < n_chan; i++) {
1161 if (chanlist[i] != chansegment[i % seglen]) {
1162 printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1163 i, CR_CHAN(chansegment[i]),
1164 CR_RANGE(chansegment[i]),
1165 CR_AREF(chansegment[i]),
1166 CR_CHAN(chanlist[i % seglen]),
1167 CR_RANGE(chanlist[i % seglen]),
1168 CR_AREF(chansegment[i % seglen]));
1169 return 0;
1170 }
1171 }
1172 return seglen;
1173 }
1174
1175 static void setup_channel_list(struct comedi_device *dev,
1176 struct comedi_subdevice *s,
1177 unsigned int *chanlist, unsigned int n_chan,
1178 unsigned int seglen)
1179 {
1180 unsigned int i, range, chanprog;
1181
1182 DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan,
1183 seglen);
1184 devpriv->act_chanlist_len = seglen;
1185 devpriv->act_chanlist_pos = 0;
1186
1187 DPRINTK("SegLen: %d\n", seglen);
1188 for (i = 0; i < seglen; i++) { /* store range list to card */
1189 chanprog = muxonechan[CR_CHAN(chanlist[i])];
1190 outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
1191 range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
1192 if (CR_AREF(chanlist[i]) == AREF_DIFF)
1193 range |= 0x0020;
1194 outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
1195 #ifdef PCI171x_PARANOIDCHECK
1196 devpriv->act_chanlist[i] =
1197 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1198 #endif
1199 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1200 devpriv->act_chanlist[i]);
1201 }
1202 #ifdef PCI171x_PARANOIDCHECK
1203 for ( ; i < n_chan; i++) { /* store remainder of channel list */
1204 devpriv->act_chanlist[i] =
1205 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
1206 }
1207 #endif
1208
1209 devpriv->ai_et_MuxVal =
1210 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
1211 /* select channel interval to scan */
1212 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
1213 DPRINTK("MUX: %4x L%4x.H%4x\n",
1214 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
1215 CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
1216 }
1217
1218 /*
1219 ==============================================================================
1220 */
1221 static void start_pacer(struct comedi_device *dev, int mode,
1222 unsigned int divisor1, unsigned int divisor2)
1223 {
1224 DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1225 divisor1, divisor2);
1226 outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
1227 outw(0x74, dev->iobase + PCI171x_CNTCTRL);
1228
1229 if (mode == 1) {
1230 outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
1231 outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
1232 outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
1233 outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
1234 }
1235 DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");
1236 }
1237
1238 /*
1239 ==============================================================================
1240 */
1241 static int pci171x_ai_cancel(struct comedi_device *dev,
1242 struct comedi_subdevice *s)
1243 {
1244 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n");
1245
1246 switch (this_board->cardtype) {
1247 default:
1248 devpriv->CntrlReg &= Control_CNT0;
1249 devpriv->CntrlReg |= Control_SW;
1250
1251 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1252 start_pacer(dev, -1, 0, 0);
1253 outb(0, dev->iobase + PCI171x_CLRFIFO);
1254 outb(0, dev->iobase + PCI171x_CLRINT);
1255 break;
1256 }
1257
1258 devpriv->ai_do = 0;
1259 devpriv->ai_act_scan = 0;
1260 s->async->cur_chan = 0;
1261 devpriv->ai_buf_ptr = 0;
1262 devpriv->neverending_ai = 0;
1263
1264 DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n");
1265 return 0;
1266 }
1267
1268 /*
1269 ==============================================================================
1270 */
1271 static int pci171x_reset(struct comedi_device *dev)
1272 {
1273 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1274 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
1275 devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */
1276 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
1277 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1278 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1279 start_pacer(dev, -1, 0, 0); /* stop 8254 */
1280 devpriv->da_ranges = 0;
1281 if (this_board->n_aochan) {
1282 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
1283 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
1284 devpriv->ao_data[0] = 0x0000;
1285 if (this_board->n_aochan > 1) {
1286 outw(0, dev->iobase + PCI171x_DA2);
1287 devpriv->ao_data[1] = 0x0000;
1288 }
1289 }
1290 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
1291 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
1292 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
1293
1294 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1295 return 0;
1296 }
1297
1298 /*
1299 ==============================================================================
1300 */
1301 static int pci1720_reset(struct comedi_device *dev)
1302 {
1303 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
1304 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
1305 devpriv->da_ranges = 0xAA;
1306 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */
1307 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
1308 outw(0x0800, dev->iobase + PCI1720_DA1);
1309 outw(0x0800, dev->iobase + PCI1720_DA2);
1310 outw(0x0800, dev->iobase + PCI1720_DA3);
1311 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
1312 devpriv->ao_data[0] = 0x0800;
1313 devpriv->ao_data[1] = 0x0800;
1314 devpriv->ao_data[2] = 0x0800;
1315 devpriv->ao_data[3] = 0x0800;
1316 DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n");
1317 return 0;
1318 }
1319
1320 /*
1321 ==============================================================================
1322 */
1323 static int pci1710_reset(struct comedi_device *dev)
1324 {
1325 DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n");
1326 switch (this_board->cardtype) {
1327 case TYPE_PCI1720:
1328 return pci1720_reset(dev);
1329 default:
1330 return pci171x_reset(dev);
1331 }
1332 DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
1333 }
1334
1335 static struct pci_dev *pci1710_find_pci_dev(struct comedi_device *dev,
1336 struct comedi_devconfig *it)
1337 {
1338 struct pci_dev *pcidev = NULL;
1339 int bus = it->options[0];
1340 int slot = it->options[1];
1341 int board_index = this_board - boardtypes;
1342 int i;
1343
1344 for_each_pci_dev(pcidev) {
1345 if (bus || slot) {
1346 if (bus != pcidev->bus->number ||
1347 slot != PCI_SLOT(pcidev->devfn))
1348 continue;
1349 }
1350 if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
1351 continue;
1352 if (strcmp(this_board->name, DRV_NAME) == 0) {
1353 for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
1354 if (pcidev->device == boardtypes[i].device_id) {
1355 board_index = i;
1356 break;
1357 }
1358 }
1359 if (i == ARRAY_SIZE(boardtypes))
1360 continue;
1361 } else {
1362 if (pcidev->device != boardtypes[board_index].device_id)
1363 continue;
1364 }
1365 dev->board_ptr = &boardtypes[board_index];
1366 return pcidev;
1367 }
1368 dev_err(dev->class_dev,
1369 "No supported board found! (req. bus %d, slot %d)\n",
1370 bus, slot);
1371 return NULL;
1372 }
1373
1374 static int pci1710_attach(struct comedi_device *dev,
1375 struct comedi_devconfig *it)
1376 {
1377 struct pci_dev *pcidev;
1378 struct comedi_subdevice *s;
1379 int ret, subdev, n_subdevices;
1380 unsigned int irq;
1381
1382 dev_info(dev->class_dev, DRV_NAME ": attach\n");
1383
1384 ret = alloc_private(dev, sizeof(struct pci1710_private));
1385 if (ret < 0)
1386 return -ENOMEM;
1387
1388 pcidev = pci1710_find_pci_dev(dev, it);
1389 if (!pcidev)
1390 return -EIO;
1391 comedi_set_hw_dev(dev, &pcidev->dev);
1392
1393 ret = comedi_pci_enable(pcidev, DRV_NAME);
1394 if (ret)
1395 return ret;
1396
1397 dev->iobase = pci_resource_start(pcidev, 2);
1398 irq = pcidev->irq;
1399
1400 dev->board_name = this_board->name;
1401
1402 n_subdevices = 0;
1403 if (this_board->n_aichan)
1404 n_subdevices++;
1405 if (this_board->n_aochan)
1406 n_subdevices++;
1407 if (this_board->n_dichan)
1408 n_subdevices++;
1409 if (this_board->n_dochan)
1410 n_subdevices++;
1411 if (this_board->n_counter)
1412 n_subdevices++;
1413
1414 ret = comedi_alloc_subdevices(dev, n_subdevices);
1415 if (ret)
1416 return ret;
1417
1418 pci1710_reset(dev);
1419
1420 if (this_board->have_irq) {
1421 if (irq) {
1422 if (request_irq(irq, interrupt_service_pci1710,
1423 IRQF_SHARED, "Advantech PCI-1710",
1424 dev)) {
1425 dev_dbg(dev->class_dev,
1426 "unable to allocate IRQ %d, DISABLING IT",
1427 irq);
1428 irq = 0; /* Can't use IRQ */
1429 } else {
1430 dev_dbg(dev->class_dev, "irq=%u", irq);
1431 }
1432 } else {
1433 dev_dbg(dev->class_dev, "IRQ disabled");
1434 }
1435 } else {
1436 irq = 0;
1437 }
1438
1439 dev->irq = irq;
1440 subdev = 0;
1441
1442 if (this_board->n_aichan) {
1443 s = dev->subdevices + subdev;
1444 dev->read_subdev = s;
1445 s->type = COMEDI_SUBD_AI;
1446 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1447 if (this_board->n_aichand)
1448 s->subdev_flags |= SDF_DIFF;
1449 s->n_chan = this_board->n_aichan;
1450 s->maxdata = this_board->ai_maxdata;
1451 s->len_chanlist = this_board->n_aichan;
1452 s->range_table = this_board->rangelist_ai;
1453 s->cancel = pci171x_ai_cancel;
1454 s->insn_read = pci171x_insn_read_ai;
1455 if (irq) {
1456 s->subdev_flags |= SDF_CMD_READ;
1457 s->do_cmdtest = pci171x_ai_cmdtest;
1458 s->do_cmd = pci171x_ai_cmd;
1459 }
1460 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
1461 subdev++;
1462 }
1463
1464 if (this_board->n_aochan) {
1465 s = dev->subdevices + subdev;
1466 s->type = COMEDI_SUBD_AO;
1467 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1468 s->n_chan = this_board->n_aochan;
1469 s->maxdata = this_board->ao_maxdata;
1470 s->len_chanlist = this_board->n_aochan;
1471 s->range_table = this_board->rangelist_ao;
1472 switch (this_board->cardtype) {
1473 case TYPE_PCI1720:
1474 s->insn_write = pci1720_insn_write_ao;
1475 break;
1476 default:
1477 s->insn_write = pci171x_insn_write_ao;
1478 break;
1479 }
1480 s->insn_read = pci171x_insn_read_ao;
1481 subdev++;
1482 }
1483
1484 if (this_board->n_dichan) {
1485 s = dev->subdevices + subdev;
1486 s->type = COMEDI_SUBD_DI;
1487 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
1488 s->n_chan = this_board->n_dichan;
1489 s->maxdata = 1;
1490 s->len_chanlist = this_board->n_dichan;
1491 s->range_table = &range_digital;
1492 s->io_bits = 0; /* all bits input */
1493 s->insn_bits = pci171x_insn_bits_di;
1494 subdev++;
1495 }
1496
1497 if (this_board->n_dochan) {
1498 s = dev->subdevices + subdev;
1499 s->type = COMEDI_SUBD_DO;
1500 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1501 s->n_chan = this_board->n_dochan;
1502 s->maxdata = 1;
1503 s->len_chanlist = this_board->n_dochan;
1504 s->range_table = &range_digital;
1505 /* all bits output */
1506 s->io_bits = (1 << this_board->n_dochan) - 1;
1507 s->state = 0;
1508 s->insn_bits = pci171x_insn_bits_do;
1509 subdev++;
1510 }
1511
1512 if (this_board->n_counter) {
1513 s = dev->subdevices + subdev;
1514 s->type = COMEDI_SUBD_COUNTER;
1515 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1516 s->n_chan = this_board->n_counter;
1517 s->len_chanlist = this_board->n_counter;
1518 s->maxdata = 0xffff;
1519 s->range_table = &range_unknown;
1520 s->insn_read = pci171x_insn_counter_read;
1521 s->insn_write = pci171x_insn_counter_write;
1522 s->insn_config = pci171x_insn_counter_config;
1523 subdev++;
1524 }
1525
1526 devpriv->valid = 1;
1527
1528 return 0;
1529 }
1530
1531 static void pci1710_detach(struct comedi_device *dev)
1532 {
1533 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1534
1535 if (dev->private) {
1536 if (devpriv->valid)
1537 pci1710_reset(dev);
1538 if (dev->irq)
1539 free_irq(dev->irq, dev);
1540 }
1541 if (pcidev) {
1542 if (dev->iobase)
1543 comedi_pci_disable(pcidev);
1544 pci_dev_put(pcidev);
1545 }
1546 }
1547
1548 static struct comedi_driver adv_pci1710_driver = {
1549 .driver_name = "adv_pci1710",
1550 .module = THIS_MODULE,
1551 .attach = pci1710_attach,
1552 .detach = pci1710_detach,
1553 .num_names = ARRAY_SIZE(boardtypes),
1554 .board_name = &boardtypes[0].name,
1555 .offset = sizeof(struct boardtype),
1556 };
1557
1558 static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev,
1559 const struct pci_device_id *ent)
1560 {
1561 return comedi_pci_auto_config(dev, &adv_pci1710_driver);
1562 }
1563
1564 static void __devexit adv_pci1710_pci_remove(struct pci_dev *dev)
1565 {
1566 comedi_pci_auto_unconfig(dev);
1567 }
1568
1569 static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
1570 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
1571 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
1572 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
1573 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
1574 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
1575 { 0 }
1576 };
1577 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1578
1579 static struct pci_driver adv_pci1710_pci_driver = {
1580 .name = "adv_pci1710",
1581 .id_table = adv_pci1710_pci_table,
1582 .probe = adv_pci1710_pci_probe,
1583 .remove = __devexit_p(adv_pci1710_pci_remove),
1584 };
1585 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1586
1587 MODULE_AUTHOR("Comedi http://www.comedi.org");
1588 MODULE_DESCRIPTION("Comedi low-level driver");
1589 MODULE_LICENSE("GPL");
This page took 0.065095 seconds and 6 git commands to generate.