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