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