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