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