Staging: comedi: adv_pci_dio: fixed multiple brace coding style issues
[deliverable/linux.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
5f74ea14 61#define DPRINTK(fmt, args...) printk(fmt, ## args)
0e8db97a
MD
62#else
63#define DPRINTK(fmt, args...)
64#endif
65
2696fb57 66/* hardware types of the cards */
0e8db97a
MD
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 */
d5a2ffd8
UKK
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 */
0e8db97a
MD
90#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
91
2696fb57 92/* upper bits from status register (PCI171x_STATUS) (lower is same woth control reg) */
0e8db97a
MD
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 */
2696fb57 97/* bits from control register (PCI171x_CONTROL) */
0e8db97a
MD
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 */
2696fb57 105/* bits from counter control register (PCI171x_CNTCTRL) */
0e8db97a
MD
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
2696fb57 123/* D/A synchronized control (PCI1720_SYNCONT) */
0e8db97a
MD
124#define Syncont_SC0 1 /* set synchronous output mode */
125
9ced1de6 126static const struct comedi_lrange range_pci1710_3 = { 9, {
0a85b6f0
MT
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 }
0e8db97a
MD
137};
138
139static const char range_codes_pci1710_3[] =
0a85b6f0 140 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 };
0e8db97a 141
9ced1de6 142static const struct comedi_lrange range_pci1710hg = { 12, {
0a85b6f0
MT
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 }
0e8db97a
MD
156};
157
158static const char range_codes_pci1710hg[] =
0a85b6f0
MT
159 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12,
160 0x13
161};
0e8db97a 162
9ced1de6 163static const struct comedi_lrange range_pci17x1 = { 5, {
0a85b6f0
MT
164 BIP_RANGE(10),
165 BIP_RANGE(5),
166 BIP_RANGE(2.5),
167 BIP_RANGE(1.25),
168 BIP_RANGE(0.625)
169 }
0e8db97a
MD
170};
171
172static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
173
9ced1de6 174static const struct comedi_lrange range_pci1720 = { 4, {
0a85b6f0
MT
175 UNI_RANGE(5),
176 UNI_RANGE(10),
177 BIP_RANGE(5),
178 BIP_RANGE(10)
179 }
0e8db97a
MD
180};
181
9ced1de6 182static const struct comedi_lrange range_pci171x_da = { 2, {
0a85b6f0
MT
183 UNI_RANGE(5),
184 UNI_RANGE(10),
185 }
0e8db97a
MD
186};
187
0a85b6f0
MT
188static int pci1710_attach(struct comedi_device *dev,
189 struct comedi_devconfig *it);
da91b269 190static int pci1710_detach(struct comedi_device *dev);
0e8db97a 191
7875a00b 192struct boardtype {
2696fb57 193 const char *name; /* board name */
0e8db97a 194 int device_id;
2696fb57
BP
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 */
7875a00b 211};
0e8db97a
MD
212
213static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
0a85b6f0
MT
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}
0e8db97a
MD
221};
222
223MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
224
7875a00b 225static const struct boardtype boardtypes[] = {
0e8db97a 226 {"pci1710", 0x1710,
0a85b6f0
MT
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},
0e8db97a 232 {"pci1710hg", 0x1710,
0a85b6f0
MT
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},
0e8db97a 238 {"pci1711", 0x1711,
0a85b6f0
MT
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},
0e8db97a 243 {"pci1713", 0x1713,
0a85b6f0
MT
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},
0e8db97a 248 {"pci1720", 0x1720,
0a85b6f0
MT
249 IORANGE_1720, 0, TYPE_PCI1720,
250 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff,
251 NULL, NULL, &range_pci1720,
252 0, 0},
0e8db97a 253 {"pci1731", 0x1731,
0a85b6f0
MT
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},
2696fb57 258 /* dummy entry corresponding to driver name */
0e8db97a
MD
259 {.name = DRV_NAME},
260};
261
7875a00b 262#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
0e8db97a 263
139dfbdf 264static struct comedi_driver driver_pci1710 = {
0e8db97a
MD
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,
7875a00b 271 .offset = sizeof(struct boardtype),
0e8db97a
MD
272};
273
6e8131a8 274struct pci1710_private {
2696fb57
BP
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 */
0e8db97a
MD
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;
2696fb57
BP
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 */
0a85b6f0 298 short *ai_data; /* data buffer */
2696fb57 299 unsigned int ai_timer1; /* timers */
0e8db97a 300 unsigned int ai_timer2;
2696fb57
BP
301 short ao_data[4]; /* data output buffer */
302 unsigned int cnt0_write_wait; /* after a write, wait for update of the internal state */
6e8131a8 303};
0e8db97a 304
6e8131a8 305#define devpriv ((struct pci1710_private *)dev->private)
7875a00b 306#define this_board ((const struct boardtype *)dev->board_ptr)
0e8db97a
MD
307
308/*
309==============================================================================
310*/
311
0a85b6f0
MT
312static int check_channel_list(struct comedi_device *dev,
313 struct comedi_subdevice *s,
314 unsigned int *chanlist, unsigned int n_chan);
315static 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);
319static void start_pacer(struct comedi_device *dev, int mode,
320 unsigned int divisor1, unsigned int divisor2);
da91b269 321static int pci1710_reset(struct comedi_device *dev);
0a85b6f0
MT
322static int pci171x_ai_cancel(struct comedi_device *dev,
323 struct comedi_subdevice *s);
0e8db97a 324
2696fb57 325static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, /* used for gain list programming */
0e8db97a
MD
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*/
0a85b6f0
MT
334static int pci171x_insn_read_ai(struct comedi_device *dev,
335 struct comedi_subdevice *s,
336 struct comedi_insn *insn, unsigned int *data)
0e8db97a
MD
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;
2696fb57 345 devpriv->CntrlReg |= Control_SW; /* set software trigger */
0e8db97a
MD
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));
5f74ea14 359 /* udelay(1); */
0e8db97a
MD
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;
0a85b6f0
MT
375 DPRINTK
376 ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n",
377 n);
0e8db97a
MD
378 return -ETIME;
379
0a85b6f0 380conv_finish:
0e8db97a
MD
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*/
0a85b6f0
MT
405static int pci171x_insn_write_ao(struct comedi_device *dev,
406 struct comedi_subdevice *s,
407 struct comedi_insn *insn, unsigned int *data)
0e8db97a
MD
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*/
0a85b6f0
MT
437static int pci171x_insn_read_ao(struct comedi_device *dev,
438 struct comedi_subdevice *s,
439 struct comedi_insn *insn, unsigned int *data)
0e8db97a
MD
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*/
0a85b6f0
MT
453static int pci171x_insn_bits_di(struct comedi_device *dev,
454 struct comedi_subdevice *s,
455 struct comedi_insn *insn, unsigned int *data)
0e8db97a
MD
456{
457 data[1] = inw(dev->iobase + PCI171x_DI);
458
459 return 2;
460}
461
462/*
463==============================================================================
464*/
0a85b6f0
MT
465static int pci171x_insn_bits_do(struct comedi_device *dev,
466 struct comedi_subdevice *s,
467 struct comedi_insn *insn, unsigned int *data)
0e8db97a
MD
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*/
0a85b6f0
MT
482static int pci171x_insn_counter_read(struct comedi_device *dev,
483 struct comedi_subdevice *s,
484 struct comedi_insn *insn,
485 unsigned int *data)
0e8db97a
MD
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*/
0a85b6f0
MT
506static int pci171x_insn_counter_write(struct comedi_device *dev,
507 struct comedi_subdevice *s,
508 struct comedi_insn *insn,
509 unsigned int *data)
0e8db97a
MD
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*/
da91b269 535static int pci171x_insn_counter_config(struct comedi_device *dev,
0a85b6f0
MT
536 struct comedi_subdevice *s,
537 struct comedi_insn *insn,
538 unsigned int *data)
0e8db97a
MD
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*/
0a85b6f0
MT
573static int pci1720_insn_write_ao(struct comedi_device *dev,
574 struct comedi_subdevice *s,
575 struct comedi_insn *insn, unsigned int *data)
0e8db97a
MD
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));
2696fb57 589 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
0e8db97a
MD
590 }
591
592 devpriv->ao_data[chan] = data[n];
593
594 return n;
595}
596
597/*
598==============================================================================
599*/
600static void interrupt_pci1710_every_sample(void *d)
601{
71b5f4f1 602 struct comedi_device *dev = d;
34c43922 603 struct comedi_subdevice *s = dev->subdevices + 0;
0e8db97a
MD
604 int m;
605#ifdef PCI171x_PARANOIDCHECK
790c5541 606 short sampl;
0e8db97a
MD
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) {
5f74ea14 612 printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
0e8db97a
MD
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) {
5f74ea14 619 printk
0a85b6f0
MT
620 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
621 dev->minor, m);
0e8db97a
MD
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
2696fb57 628 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
0e8db97a
MD
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) !=
0a85b6f0 637 devpriv->act_chanlist[s->async->cur_chan]) {
5f74ea14 638 printk
0a85b6f0
MT
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);
0e8db97a
MD
645 pci171x_ai_cancel(dev, s);
646 s->async->events |=
0a85b6f0 647 COMEDI_CB_EOA | COMEDI_CB_ERROR;
0e8db97a
MD
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,
0a85b6f0 656 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
0e8db97a
MD
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
2696fb57 664 if (s->async->cur_chan == 0) { /* one scan done */
0e8db97a 665 devpriv->ai_act_scan++;
0a85b6f0
MT
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);
0e8db97a 670 DPRINTK("adv_pci1710 EDBG: EOS2\n");
2696fb57 671 if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */
0e8db97a
MD
672 pci171x_ai_cancel(dev, s);
673 s->async->events |= COMEDI_CB_EOA;
674 comedi_event(dev, s);
675 return;
676 }
677 }
678 }
679
2696fb57 680 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
0e8db97a
MD
681 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n");
682
683 comedi_event(dev, s);
684}
685
686/*
687==============================================================================
688*/
0a85b6f0
MT
689static int move_block_from_fifo(struct comedi_device *dev,
690 struct comedi_subdevice *s, int n, int turn)
0e8db97a
MD
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]) {
5f74ea14 704 printk
0a85b6f0
MT
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);
0e8db97a
MD
710 pci171x_ai_cancel(dev, s);
711 s->async->events |=
0a85b6f0 712 COMEDI_CB_EOA | COMEDI_CB_ERROR;
0e8db97a
MD
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,
0a85b6f0 719 inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
0e8db97a
MD
720#endif
721 j++;
722 if (j >= devpriv->ai_n_chan) {
723 j = 0;
724 devpriv->ai_act_scan++;
725 }
726 }
61283d22 727 s->async->cur_chan = j;
0e8db97a
MD
728 DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n");
729 return 0;
730}
731
732/*
733==============================================================================
734*/
735static void interrupt_pci1710_half_fifo(void *d)
736{
71b5f4f1 737 struct comedi_device *dev = d;
34c43922 738 struct comedi_subdevice *s = dev->subdevices + 0;
0e8db97a
MD
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)) {
5f74ea14 744 printk("comedi%d: A/D FIFO not half full! (%4x)\n",
0a85b6f0 745 dev->minor, m);
0e8db97a
MD
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) {
5f74ea14 752 printk
0a85b6f0
MT
753 ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
754 dev->minor, m);
0e8db97a
MD
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;
790c5541
BP
762 if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
763 m = devpriv->ai_data_len / sizeof(short);
0e8db97a
MD
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 }
2696fb57 781 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
0e8db97a
MD
782 DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n");
783
784 comedi_event(dev, s);
785}
786
787/*
788==============================================================================
789*/
70265d24 790static irqreturn_t interrupt_service_pci1710(int irq, void *d)
0e8db97a 791{
71b5f4f1 792 struct comedi_device *dev = d;
0e8db97a
MD
793
794 DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n",
795 irq);
2696fb57
BP
796 if (!dev->attached) /* is device attached? */
797 return IRQ_NONE; /* no, exit */
0e8db97a 798
2696fb57
BP
799 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */
800 return IRQ_NONE; /* no, exit */
0e8db97a
MD
801
802 DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
803 inw(dev->iobase + PCI171x_STATUS));
804
2696fb57 805 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
0e8db97a
MD
806 devpriv->ai_et = 0;
807 devpriv->CntrlReg &= Control_CNT0;
2696fb57 808 devpriv->CntrlReg |= Control_SW; /* set software trigger */
0e8db97a
MD
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);
2696fb57 815 /* start pacer */
0e8db97a
MD
816 start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
817 return IRQ_HANDLED;
818 }
2696fb57 819 if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
0e8db97a
MD
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*/
da91b269 831static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
0a85b6f0 832 struct comedi_subdevice *s)
0e8db97a 833{
48b1aff5 834 unsigned int divisor1 = 0, divisor2 = 0;
0e8db97a
MD
835 unsigned int seglen;
836
837 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n",
838 mode);
2696fb57 839 start_pacer(dev, -1, 0, 0); /* stop pacer */
0e8db97a
MD
840
841 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 842 devpriv->ai_n_chan);
0e8db97a
MD
843 if (seglen < 1)
844 return -EINVAL;
845 setup_channel_list(dev, s, devpriv->ai_chanlist,
0a85b6f0 846 devpriv->ai_n_chan, seglen);
0e8db97a
MD
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;
2696fb57 859 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
0e8db97a
MD
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;
0a85b6f0 868 } /* well, user want neverending */
0e8db97a
MD
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 &=
0a85b6f0 881 ~(Control_PACER | Control_ONEFH | Control_GATE);
0e8db97a
MD
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,
0a85b6f0
MT
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);
0e8db97a
MD
894 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
895 if (mode != 2) {
2696fb57 896 /* start pacer */
0e8db97a
MD
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*/
da91b269 917static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd)
0e8db97a 918{
5f74ea14 919 printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
0a85b6f0 920 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
5f74ea14 921 printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
0a85b6f0 922 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
5f74ea14 923 printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src,
0a85b6f0 924 cmd->scan_end_src);
5f74ea14 925 printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
0a85b6f0 926 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
0e8db97a
MD
927}
928#endif
929
930/*
931==============================================================================
932*/
0a85b6f0
MT
933static int pci171x_ai_cmdtest(struct comedi_device *dev,
934 struct comedi_subdevice *s,
935 struct comedi_cmd *cmd)
0e8db97a
MD
936{
937 int err = 0;
48b1aff5 938 int tmp, divisor1 = 0, divisor2 = 0;
0e8db97a
MD
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
0a85b6f0
MT
975 DPRINTK
976 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
977 err);
0e8db97a
MD
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
0a85b6f0
MT
1008 DPRINTK
1009 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
1010 err);
0e8db97a
MD
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
0e8db97a
MD
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
0a85b6f0
MT
1058 DPRINTK
1059 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
1060 err);
0e8db97a
MD
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,
0a85b6f0
MT
1069 &divisor2, &cmd->convert_arg,
1070 cmd->flags & TRIG_ROUND_MASK);
0e8db97a
MD
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) {
0a85b6f0
MT
1078 DPRINTK
1079 ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n",
1080 err);
0e8db97a
MD
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,
0a85b6f0 1088 cmd->chanlist_len))
2696fb57 1089 return 5; /* incorrect channels list */
0e8db97a
MD
1090 }
1091
1092 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n");
1093 return 0;
1094}
1095
1096/*
1097==============================================================================
1098*/
da91b269 1099static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
0e8db97a 1100{
ea6d0d4c 1101 struct comedi_cmd *cmd = &s->async->cmd;
0e8db97a
MD
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
2696fb57
BP
1118 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
1119 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
0e8db97a
MD
1120 devpriv->ai_timer1 = cmd->convert_arg;
1121 return pci171x_ai_docmd_and_mode(cmd->start_src ==
0a85b6f0
MT
1122 TRIG_EXT ? 2 : 1, dev,
1123 s);
0e8db97a 1124 }
2696fb57 1125 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
0e8db97a
MD
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*/
0a85b6f0
MT
1139static int check_channel_list(struct comedi_device *dev,
1140 struct comedi_subdevice *s,
1141 unsigned int *chanlist, unsigned int n_chan)
0e8db97a
MD
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) {
2696fb57
BP
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 */
5f74ea14 1156 /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
0e8db97a 1157 if (chanlist[0] == chanlist[i])
2696fb57
BP
1158 break; /* we detect loop, this must by finish */
1159 if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */
0e8db97a
MD
1160 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
1161 comedi_error(dev,
0a85b6f0 1162 "Odd channel can't be differential input!\n");
0e8db97a
MD
1163 return 0;
1164 }
1165 nowmustbechan =
0a85b6f0 1166 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
0e8db97a
MD
1167 if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
1168 nowmustbechan = (nowmustbechan + 1) % s->n_chan;
2696fb57 1169 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */
5f74ea14 1170 printk
0a85b6f0
MT
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]));
0e8db97a
MD
1174 return 0;
1175 }
2696fb57 1176 chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
0e8db97a
MD
1177 }
1178
2696fb57 1179 for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */
5f74ea14 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])); */
0e8db97a 1181 if (chanlist[i] != chansegment[i % seglen]) {
5f74ea14 1182 printk
0a85b6f0
MT
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]));
2696fb57 1190 return 0; /* chan/gain list is strange */
0e8db97a
MD
1191 }
1192 }
1193 } else {
1194 seglen = 1;
1195 }
1196 return seglen;
1197}
1198
0a85b6f0
MT
1199static 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)
0e8db97a
MD
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);
2696fb57 1212 for (i = 0; i < seglen; i++) { /* store range list to card */
0e8db97a
MD
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] =
0a85b6f0 1221 (CR_CHAN(chanlist[i]) << 12) & 0xf000;
0e8db97a
MD
1222#endif
1223 DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
1224 devpriv->act_chanlist[i]);
1225 }
61283d22
IA
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
0e8db97a
MD
1232
1233 devpriv->ai_et_MuxVal =
0a85b6f0 1234 CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
0e8db97a
MD
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*/
0a85b6f0
MT
1244static void start_pacer(struct comedi_device *dev, int mode,
1245 unsigned int divisor1, unsigned int divisor2)
0e8db97a
MD
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*/
0a85b6f0
MT
1264static int pci171x_ai_cancel(struct comedi_device *dev,
1265 struct comedi_subdevice *s)
0e8db97a
MD
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
2696fb57 1274 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
0e8db97a
MD
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*/
da91b269 1294static int pci171x_reset(struct comedi_device *dev)
0e8db97a
MD
1295{
1296 DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n");
1297 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
2696fb57
BP
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 */
0e8db97a
MD
1303 devpriv->da_ranges = 0;
1304 if (this_board->n_aochan) {
2696fb57
BP
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 */
0e8db97a
MD
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 }
2696fb57
BP
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 */
0e8db97a
MD
1316
1317 DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n");
1318 return 0;
1319}
1320
1321/*
1322==============================================================================
1323*/
da91b269 1324static int pci1720_reset(struct comedi_device *dev)
0e8db97a
MD
1325{
1326 DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n");
2696fb57 1327 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */
0e8db97a 1328 devpriv->da_ranges = 0xAA;
2696fb57
BP
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 */
0e8db97a
MD
1331 outw(0x0800, dev->iobase + PCI1720_DA1);
1332 outw(0x0800, dev->iobase + PCI1720_DA2);
1333 outw(0x0800, dev->iobase + PCI1720_DA3);
2696fb57 1334 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
0e8db97a
MD
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*/
da91b269 1346static int pci1710_reset(struct comedi_device *dev)
0e8db97a
MD
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*/
0a85b6f0
MT
1361static int pci1710_attach(struct comedi_device *dev,
1362 struct comedi_devconfig *it)
0e8db97a 1363{
34c43922 1364 struct comedi_subdevice *s;
0e8db97a
MD
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
5f74ea14 1375 printk("comedi%d: adv_pci1710: ", dev->minor);
0e8db97a
MD
1376
1377 opt_bus = it->options[0];
1378 opt_slot = it->options[1];
1379
c3744138
BP
1380 ret = alloc_private(dev, sizeof(struct pci1710_private));
1381 if (ret < 0) {
5f74ea14 1382 printk(" - Allocation failed!\n");
0e8db97a
MD
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,
0a85b6f0
MT
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) {
0e8db97a
MD
1395 board_index = i;
1396 break;
1397 }
1398 }
0a85b6f0
MT
1399 if (i == n_boardtypes)
1400 continue;
1401 } else {
1402 if (pcidev->device != boardtypes[board_index].device_id)
1403 continue;
0e8db97a
MD
1404 }
1405
1406 /* Found matching vendor/device. */
1407 if (opt_bus || opt_slot) {
1408 /* Check bus/slot. */
1409 if (opt_bus != pcidev->bus->number
0a85b6f0 1410 || opt_slot != PCI_SLOT(pcidev->devfn))
0e8db97a
MD
1411 continue; /* no match */
1412 }
1413 /*
0a85b6f0
MT
1414 * Look for device that isn't in use.
1415 * Enable PCI device and request regions.
1416 */
0e8db97a 1417 if (comedi_pci_enable(pcidev, DRV_NAME)) {
0a85b6f0
MT
1418 errstr =
1419 "failed to enable PCI device and request regions!";
0e8db97a
MD
1420 continue;
1421 }
2696fb57 1422 /* fixup board_ptr in case we were using the dummy entry with the driver name */
0e8db97a
MD
1423 dev->board_ptr = &boardtypes[board_index];
1424 break;
1425 }
1426
1427 if (!pcidev) {
1428 if (opt_bus || opt_slot) {
5f74ea14 1429 printk(" - Card at b:s %d:%d %s\n",
0a85b6f0 1430 opt_bus, opt_slot, errstr);
0e8db97a 1431 } else {
5f74ea14 1432 printk(" - Card %s\n", errstr);
0e8db97a
MD
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
5f74ea14 1443 printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func,
0a85b6f0 1444 iobase);
0e8db97a
MD
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
c3744138
BP
1463 ret = alloc_subdevices(dev, n_subdevices);
1464 if (ret < 0) {
5f74ea14 1465 printk(" - Allocation failed!\n");
0e8db97a
MD
1466 return ret;
1467 }
1468
1469 pci1710_reset(dev);
1470
1471 if (this_board->have_irq) {
1472 if (irq) {
5f74ea14 1473 if (request_irq(irq, interrupt_service_pci1710,
0e8db97a
MD
1474 IRQF_SHARED, "Advantech PCI-1710",
1475 dev)) {
5f74ea14 1476 printk
0a85b6f0
MT
1477 (", unable to allocate IRQ %d, DISABLING IT",
1478 irq);
0e8db97a
MD
1479 irq = 0; /* Can't use IRQ */
1480 } else {
5f74ea14 1481 printk(", irq=%u", irq);
0e8db97a
MD
1482 }
1483 } else {
5f74ea14 1484 printk(", IRQ disabled");
0e8db97a
MD
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 }
2696fb57 1514 devpriv->i8254_osc_base = 100; /* 100ns=10MHz */
0e8db97a
MD
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*/
da91b269 1587static int pci1710_detach(struct comedi_device *dev)
0e8db97a
MD
1588{
1589
1590 if (dev->private) {
1591 if (devpriv->valid)
1592 pci1710_reset(dev);
1593 if (dev->irq)
5f74ea14 1594 free_irq(dev->irq, dev);
0e8db97a
MD
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*/
1609COMEDI_PCI_INITCLEANUP(driver_pci1710, pci1710_pci_table);
1610/*
1611==============================================================================
1612*/
This page took 0.215294 seconds and 5 git commands to generate.