Merge tag 'for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux...
[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,
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
0e8db97a
MD
54#define PCI171x_AD_DATA 0 /* R: A/D data */
55#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
56#define PCI171x_RANGE 2 /* W: A/D gain/range register */
57#define PCI171x_MUX 4 /* W: A/D multiplexor control */
58#define PCI171x_STATUS 6 /* R: status register */
59#define PCI171x_CONTROL 6 /* W: control register */
60#define PCI171x_CLRINT 8 /* W: clear interrupts request */
61#define PCI171x_CLRFIFO 9 /* W: clear FIFO */
62#define PCI171x_DA1 10 /* W: D/A register */
63#define PCI171x_DA2 12 /* W: D/A register */
64#define PCI171x_DAREF 14 /* W: D/A reference control */
65#define PCI171x_DI 16 /* R: digi inputs */
66#define PCI171x_DO 16 /* R: digi inputs */
925ddefc
HS
67
68#define PCI171X_TIMER_BASE 0x18
69
d5a2ffd8
UKK
70#define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
71#define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
72#define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
0e8db97a
MD
73#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
74
97feeef5
M
75/* upper bits from status register (PCI171x_STATUS) (lower is same with control
76 * reg) */
0e8db97a
MD
77#define Status_FE 0x0100 /* 1=FIFO is empty */
78#define Status_FH 0x0200 /* 1=FIFO is half full */
79#define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
25985edc 80#define Status_IRQ 0x0800 /* 1=IRQ occurred */
2696fb57 81/* bits from control register (PCI171x_CONTROL) */
97feeef5
M
82#define Control_CNT0 0x0040 /* 1=CNT0 have external source,
83 * 0=have internal 100kHz source */
0e8db97a
MD
84#define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
85#define Control_IRQEN 0x0010 /* 1=enable IRQ */
86#define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
87#define Control_EXT 0x0004 /* 1=external trigger source */
88#define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
89#define Control_SW 0x0001 /* 1=enable software trigger source */
2696fb57 90/* bits from counter control register (PCI171x_CNTCTRL) */
0e8db97a
MD
91#define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
92#define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
93#define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
94#define Counter_M2 0x0008
95#define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
96#define Counter_RW1 0x0020
97#define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
97feeef5
M
98#define Counter_SC1 0x0080 /* be used, 00 for CNT0,
99 * 11 for read-back command */
0e8db97a
MD
100
101#define PCI1720_DA0 0 /* W: D/A register 0 */
102#define PCI1720_DA1 2 /* W: D/A register 1 */
103#define PCI1720_DA2 4 /* W: D/A register 2 */
104#define PCI1720_DA3 6 /* W: D/A register 3 */
105#define PCI1720_RANGE 8 /* R/W: D/A range register */
106#define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
107#define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
108
2696fb57 109/* D/A synchronized control (PCI1720_SYNCONT) */
0e8db97a
MD
110#define Syncont_SC0 1 /* set synchronous output mode */
111
bdaa6140
HS
112static const struct comedi_lrange range_pci1710_3 = {
113 9, {
114 BIP_RANGE(5),
115 BIP_RANGE(2.5),
116 BIP_RANGE(1.25),
117 BIP_RANGE(0.625),
118 BIP_RANGE(10),
119 UNI_RANGE(10),
120 UNI_RANGE(5),
121 UNI_RANGE(2.5),
122 UNI_RANGE(1.25)
123 }
0e8db97a
MD
124};
125
97feeef5
M
126static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
127 0x10, 0x11, 0x12, 0x13 };
0e8db97a 128
bdaa6140
HS
129static const struct comedi_lrange range_pci1710hg = {
130 12, {
131 BIP_RANGE(5),
132 BIP_RANGE(0.5),
133 BIP_RANGE(0.05),
134 BIP_RANGE(0.005),
135 BIP_RANGE(10),
136 BIP_RANGE(1),
137 BIP_RANGE(0.1),
138 BIP_RANGE(0.01),
139 UNI_RANGE(10),
140 UNI_RANGE(1),
141 UNI_RANGE(0.1),
142 UNI_RANGE(0.01)
143 }
0e8db97a
MD
144};
145
97feeef5
M
146static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
147 0x05, 0x06, 0x07, 0x10, 0x11,
148 0x12, 0x13 };
0e8db97a 149
bdaa6140
HS
150static const struct comedi_lrange range_pci17x1 = {
151 5, {
152 BIP_RANGE(10),
153 BIP_RANGE(5),
154 BIP_RANGE(2.5),
155 BIP_RANGE(1.25),
156 BIP_RANGE(0.625)
157 }
0e8db97a
MD
158};
159
160static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
161
7a772eea 162static const struct comedi_lrange pci1720_ao_range = {
bdaa6140
HS
163 4, {
164 UNI_RANGE(5),
165 UNI_RANGE(10),
166 BIP_RANGE(5),
167 BIP_RANGE(10)
168 }
0e8db97a
MD
169};
170
7a772eea 171static const struct comedi_lrange pci171x_ao_range = {
bdaa6140
HS
172 2, {
173 UNI_RANGE(5),
174 UNI_RANGE(10)
175 }
0e8db97a
MD
176};
177
0005fbed
HS
178enum pci1710_boardid {
179 BOARD_PCI1710,
94cc409b 180 BOARD_PCI1710HG,
0005fbed
HS
181 BOARD_PCI1711,
182 BOARD_PCI1713,
183 BOARD_PCI1720,
184 BOARD_PCI1731,
185};
186
7875a00b 187struct boardtype {
2696fb57 188 const char *name; /* board name */
2696fb57 189 int n_aichan; /* num of A/D chans */
2696fb57
BP
190 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
191 const char *rangecode_ai; /* range codes for programming */
e4451eeb
HS
192 unsigned int is_pci1713:1;
193 unsigned int is_pci1720:1;
0b25aa79 194 unsigned int has_irq:1;
7bd428c4 195 unsigned int has_large_fifo:1; /* 4K or 1K FIFO */
177a0729 196 unsigned int has_diff_ai:1;
87abf660 197 unsigned int has_ao:1;
068de2b6 198 unsigned int has_di_do:1;
c5b6b544 199 unsigned int has_counter:1;
7875a00b 200};
0e8db97a 201
7875a00b 202static const struct boardtype boardtypes[] = {
0005fbed 203 [BOARD_PCI1710] = {
e199ec95 204 .name = "pci1710",
e199ec95 205 .n_aichan = 16,
e199ec95
HS
206 .rangelist_ai = &range_pci1710_3,
207 .rangecode_ai = range_codes_pci1710_3,
0b25aa79 208 .has_irq = 1,
7bd428c4 209 .has_large_fifo = 1,
177a0729 210 .has_diff_ai = 1,
87abf660 211 .has_ao = 1,
068de2b6 212 .has_di_do = 1,
c5b6b544 213 .has_counter = 1,
94cc409b
IA
214 },
215 [BOARD_PCI1710HG] = {
216 .name = "pci1710hg",
94cc409b 217 .n_aichan = 16,
e199ec95
HS
218 .rangelist_ai = &range_pci1710hg,
219 .rangecode_ai = range_codes_pci1710hg,
0b25aa79 220 .has_irq = 1,
7bd428c4 221 .has_large_fifo = 1,
177a0729 222 .has_diff_ai = 1,
87abf660 223 .has_ao = 1,
068de2b6 224 .has_di_do = 1,
c5b6b544 225 .has_counter = 1,
0005fbed
HS
226 },
227 [BOARD_PCI1711] = {
e199ec95 228 .name = "pci1711",
e199ec95 229 .n_aichan = 16,
e199ec95
HS
230 .rangelist_ai = &range_pci17x1,
231 .rangecode_ai = range_codes_pci17x1,
0b25aa79 232 .has_irq = 1,
87abf660 233 .has_ao = 1,
068de2b6 234 .has_di_do = 1,
c5b6b544 235 .has_counter = 1,
0005fbed
HS
236 },
237 [BOARD_PCI1713] = {
e199ec95 238 .name = "pci1713",
e199ec95 239 .n_aichan = 32,
e199ec95
HS
240 .rangelist_ai = &range_pci1710_3,
241 .rangecode_ai = range_codes_pci1710_3,
e4451eeb 242 .is_pci1713 = 1,
0b25aa79 243 .has_irq = 1,
7bd428c4 244 .has_large_fifo = 1,
177a0729 245 .has_diff_ai = 1,
0005fbed
HS
246 },
247 [BOARD_PCI1720] = {
e199ec95 248 .name = "pci1720",
e4451eeb 249 .is_pci1720 = 1,
87abf660 250 .has_ao = 1,
0005fbed
HS
251 },
252 [BOARD_PCI1731] = {
e199ec95 253 .name = "pci1731",
e199ec95 254 .n_aichan = 16,
e199ec95
HS
255 .rangelist_ai = &range_pci17x1,
256 .rangecode_ai = range_codes_pci17x1,
0b25aa79 257 .has_irq = 1,
068de2b6 258 .has_di_do = 1,
e199ec95 259 },
0e8db97a
MD
260};
261
6e8131a8 262struct pci1710_private {
7bd428c4 263 unsigned int max_samples;
2696fb57 264 unsigned int CntrlReg; /* Control register */
0e8db97a
MD
265 unsigned char ai_et;
266 unsigned int ai_et_CntrlReg;
267 unsigned int ai_et_MuxVal;
73bcf01c
HS
268 unsigned int next_divisor1;
269 unsigned int next_divisor2;
270 unsigned int divisor1;
271 unsigned int divisor2;
20ce161d 272 unsigned int act_chanlist[32]; /* list of scanned channel */
56556577 273 unsigned char saved_seglen; /* len of the non-repeating chanlist */
2696fb57 274 unsigned char da_ranges; /* copy of D/A outpit range register */
97feeef5
M
275 unsigned int cnt0_write_wait; /* after a write, wait for update of the
276 * internal state */
6e8131a8 277};
0e8db97a 278
7cc054d0
HS
279static int pci171x_ai_check_chanlist(struct comedi_device *dev,
280 struct comedi_subdevice *s,
281 struct comedi_cmd *cmd)
4fa7bbec 282{
56556577 283 struct pci1710_private *devpriv = dev->private;
b5a7a466
HS
284 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
285 unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
286 unsigned int next_chan = (chan0 + 1) % s->n_chan;
4fa7bbec 287 unsigned int chansegment[32];
b5a7a466
HS
288 unsigned int seglen;
289 int i;
4fa7bbec 290
56556577
HS
291 if (cmd->chanlist_len == 1) {
292 devpriv->saved_seglen = cmd->chanlist_len;
293 return 0;
294 }
4fa7bbec 295
b5a7a466
HS
296 /* first channel is always ok */
297 chansegment[0] = cmd->chanlist[0];
298
299 for (i = 1; i < cmd->chanlist_len; i++) {
300 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
301 unsigned int aref = CR_AREF(cmd->chanlist[i]);
302
303 if (cmd->chanlist[0] == cmd->chanlist[i])
4fa7bbec 304 break; /* we detected a loop, stop */
b5a7a466
HS
305
306 if (aref == AREF_DIFF && (chan & 1)) {
307 dev_err(dev->class_dev,
308 "Odd channel cannot be differential input!\n");
56556577 309 return -EINVAL;
4fa7bbec 310 }
b5a7a466
HS
311
312 if (last_aref == AREF_DIFF)
313 next_chan = (next_chan + 1) % s->n_chan;
314 if (chan != next_chan) {
315 dev_err(dev->class_dev,
316 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
317 i, chan, next_chan, chan0);
56556577 318 return -EINVAL;
4fa7bbec 319 }
4fa7bbec 320
b5a7a466
HS
321 /* next correct channel in list */
322 chansegment[i] = cmd->chanlist[i];
323 last_aref = aref;
324 }
325 seglen = i;
326
327 for (i = 0; i < cmd->chanlist_len; i++) {
328 if (cmd->chanlist[i] != chansegment[i % seglen]) {
329 dev_err(dev->class_dev,
330 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
331 i, CR_CHAN(chansegment[i]),
332 CR_RANGE(chansegment[i]),
333 CR_AREF(chansegment[i]),
334 CR_CHAN(cmd->chanlist[i % seglen]),
335 CR_RANGE(cmd->chanlist[i % seglen]),
336 CR_AREF(chansegment[i % seglen]));
56556577 337 return -EINVAL;
4fa7bbec
HS
338 }
339 }
56556577
HS
340 devpriv->saved_seglen = seglen;
341
342 return 0;
4fa7bbec
HS
343}
344
a65e1419
HS
345static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
346 struct comedi_subdevice *s,
347 unsigned int *chanlist,
348 unsigned int n_chan,
349 unsigned int seglen)
4fa7bbec 350{
383fab40 351 const struct boardtype *board = dev->board_ptr;
4fa7bbec 352 struct pci1710_private *devpriv = dev->private;
a65e1419
HS
353 unsigned int first_chan = CR_CHAN(chanlist[0]);
354 unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
355 unsigned int i;
0e8db97a 356
4fa7bbec 357 for (i = 0; i < seglen; i++) { /* store range list to card */
a65e1419
HS
358 unsigned int chan = CR_CHAN(chanlist[i]);
359 unsigned int range = CR_RANGE(chanlist[i]);
360 unsigned int aref = CR_AREF(chanlist[i]);
361 unsigned int rangeval;
362
363 rangeval = board->rangecode_ai[range];
364 if (aref == AREF_DIFF)
365 rangeval |= 0x0020;
366
367 /* select channel and set range */
368 outw(chan | (chan << 8), dev->iobase + PCI171x_MUX);
369 outw(rangeval, dev->iobase + PCI171x_RANGE);
370
371 devpriv->act_chanlist[i] = chan;
4fa7bbec 372 }
133dfbfb
HS
373 for ( ; i < n_chan; i++) /* store remainder of channel list */
374 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
4fa7bbec 375
4fa7bbec 376 /* select channel interval to scan */
a65e1419 377 devpriv->ai_et_MuxVal = first_chan | (last_chan << 8);
4fa7bbec
HS
378 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
379}
0e8db97a 380
fa3fa1de
HS
381static int pci171x_ai_eoc(struct comedi_device *dev,
382 struct comedi_subdevice *s,
383 struct comedi_insn *insn,
384 unsigned long context)
385{
386 unsigned int status;
387
388 status = inw(dev->iobase + PCI171x_STATUS);
389 if ((status & Status_FE) == 0)
390 return 0;
391 return -EBUSY;
392}
393
7fd2dae2
HS
394static int pci171x_ai_read_sample(struct comedi_device *dev,
395 struct comedi_subdevice *s,
396 unsigned int cur_chan,
397 unsigned int *val)
398{
399 const struct boardtype *board = dev->board_ptr;
400 struct pci1710_private *devpriv = dev->private;
401 unsigned int sample;
402 unsigned int chan;
403
404 sample = inw(dev->iobase + PCI171x_AD_DATA);
405 if (!board->is_pci1713) {
406 /*
407 * The upper 4 bits of the 16-bit sample are the channel number
408 * that the sample was acquired from. Verify that this channel
409 * number matches the expected channel number.
410 */
411 chan = sample >> 12;
412 if (chan != devpriv->act_chanlist[cur_chan]) {
413 dev_err(dev->class_dev,
414 "A/D data droput: received from channel %d, expected %d\n",
415 chan, devpriv->act_chanlist[cur_chan]);
416 return -ENODATA;
417 }
418 }
419 *val = sample & s->maxdata;
420 return 0;
421}
422
fc8e8689 423static int pci171x_ai_insn_read(struct comedi_device *dev,
0a85b6f0 424 struct comedi_subdevice *s,
fc8e8689
HS
425 struct comedi_insn *insn,
426 unsigned int *data)
0e8db97a 427{
6bd65164 428 struct pci1710_private *devpriv = dev->private;
16c7eb60
HS
429 int ret = 0;
430 int i;
0e8db97a 431
0e8db97a 432 devpriv->CntrlReg &= Control_CNT0;
2696fb57 433 devpriv->CntrlReg |= Control_SW; /* set software trigger */
0e8db97a
MD
434 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
435 outb(0, dev->iobase + PCI171x_CLRFIFO);
436 outb(0, dev->iobase + PCI171x_CLRINT);
437
a65e1419 438 pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
0e8db97a 439
16c7eb60
HS
440 for (i = 0; i < insn->n; i++) {
441 unsigned int val;
442
0e8db97a 443 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
fa3fa1de
HS
444
445 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
16c7eb60
HS
446 if (ret)
447 break;
0e8db97a 448
abe46b89 449 ret = pci171x_ai_read_sample(dev, s, 0, &val);
16c7eb60
HS
450 if (ret)
451 break;
0e8db97a 452
7fd2dae2 453 data[i] = val;
0e8db97a
MD
454 }
455
456 outb(0, dev->iobase + PCI171x_CLRFIFO);
457 outb(0, dev->iobase + PCI171x_CLRINT);
458
16c7eb60 459 return ret ? ret : insn->n;
0e8db97a
MD
460}
461
2d21fc22 462static int pci171x_ao_insn_write(struct comedi_device *dev,
0a85b6f0 463 struct comedi_subdevice *s,
2d21fc22
HS
464 struct comedi_insn *insn,
465 unsigned int *data)
0e8db97a 466{
6bd65164 467 struct pci1710_private *devpriv = dev->private;
2d21fc22
HS
468 unsigned int chan = CR_CHAN(insn->chanspec);
469 unsigned int range = CR_RANGE(insn->chanspec);
470 unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
471 unsigned int val = s->readback[chan];
472 int i;
473
474 devpriv->da_ranges &= ~(1 << (chan << 1));
475 devpriv->da_ranges |= (range << (chan << 1));
476 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
0e8db97a 477
2d21fc22
HS
478 for (i = 0; i < insn->n; i++) {
479 val = data[i];
480 outw(val, dev->iobase + reg);
1e85c1ea 481 }
0e8db97a 482
e4623cee 483 s->readback[chan] = val;
0e8db97a 484
2d21fc22 485 return insn->n;
0e8db97a
MD
486}
487
1fbe6e91 488static int pci171x_di_insn_bits(struct comedi_device *dev,
0a85b6f0 489 struct comedi_subdevice *s,
1fbe6e91
HS
490 struct comedi_insn *insn,
491 unsigned int *data)
0e8db97a
MD
492{
493 data[1] = inw(dev->iobase + PCI171x_DI);
494
a2714e3e 495 return insn->n;
0e8db97a
MD
496}
497
1fbe6e91 498static int pci171x_do_insn_bits(struct comedi_device *dev,
0a85b6f0 499 struct comedi_subdevice *s,
97f4289a
HS
500 struct comedi_insn *insn,
501 unsigned int *data)
0e8db97a 502{
97f4289a 503 if (comedi_dio_update_state(s, data))
0e8db97a 504 outw(s->state, dev->iobase + PCI171x_DO);
97f4289a 505
0e8db97a
MD
506 data[1] = s->state;
507
a2714e3e 508 return insn->n;
0e8db97a
MD
509}
510
925ddefc
HS
511static void pci171x_start_pacer(struct comedi_device *dev,
512 bool load_counters)
4fa7bbec 513{
925ddefc
HS
514 struct pci1710_private *devpriv = dev->private;
515 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
516
517 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
518 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
519
520 if (load_counters) {
521 i8254_write(timer_base, 1, 2, devpriv->divisor2);
522 i8254_write(timer_base, 1, 1, devpriv->divisor1);
4fa7bbec
HS
523 }
524}
525
db2c4a05 526static int pci171x_counter_insn_read(struct comedi_device *dev,
0a85b6f0
MT
527 struct comedi_subdevice *s,
528 struct comedi_insn *insn,
529 unsigned int *data)
0e8db97a
MD
530{
531 unsigned int msb, lsb, ccntrl;
532 int i;
533
534 ccntrl = 0xD2; /* count only */
535 for (i = 0; i < insn->n; i++) {
536 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
537
538 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
539 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
540
541 data[0] = lsb | (msb << 8);
542 }
543
544 return insn->n;
545}
546
db2c4a05 547static int pci171x_counter_insn_write(struct comedi_device *dev,
0a85b6f0
MT
548 struct comedi_subdevice *s,
549 struct comedi_insn *insn,
550 unsigned int *data)
0e8db97a 551{
6bd65164 552 struct pci1710_private *devpriv = dev->private;
0e8db97a
MD
553 uint msb, lsb, ccntrl, status;
554
555 lsb = data[0] & 0x00FF;
556 msb = (data[0] & 0xFF00) >> 8;
557
558 /* write lsb, then msb */
559 outw(lsb, dev->iobase + PCI171x_CNT0);
560 outw(msb, dev->iobase + PCI171x_CNT0);
561
562 if (devpriv->cnt0_write_wait) {
563 /* wait for the new count to be loaded */
564 ccntrl = 0xE2;
565 do {
566 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
567 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
568 } while (status & 0x40);
569 }
570
571 return insn->n;
572}
573
db2c4a05 574static int pci171x_counter_insn_config(struct comedi_device *dev,
0a85b6f0
MT
575 struct comedi_subdevice *s,
576 struct comedi_insn *insn,
577 unsigned int *data)
0e8db97a
MD
578{
579#ifdef unused
580 /* This doesn't work like a normal Comedi counter config */
6bd65164 581 struct pci1710_private *devpriv = dev->private;
0e8db97a
MD
582 uint ccntrl = 0;
583
584 devpriv->cnt0_write_wait = data[0] & 0x20;
585
586 /* internal or external clock? */
587 if (!(data[0] & 0x10)) { /* internal */
588 devpriv->CntrlReg &= ~Control_CNT0;
589 } else {
590 devpriv->CntrlReg |= Control_CNT0;
591 }
592 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
593
594 if (data[0] & 0x01)
595 ccntrl |= Counter_M0;
596 if (data[0] & 0x02)
597 ccntrl |= Counter_M1;
598 if (data[0] & 0x04)
599 ccntrl |= Counter_M2;
600 if (data[0] & 0x08)
601 ccntrl |= Counter_BCD;
602 ccntrl |= Counter_RW0; /* set read/write mode */
603 ccntrl |= Counter_RW1;
604 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
605#endif
606
607 return 1;
608}
609
3e5cf6d4 610static int pci1720_ao_insn_write(struct comedi_device *dev,
0a85b6f0 611 struct comedi_subdevice *s,
3e5cf6d4
HS
612 struct comedi_insn *insn,
613 unsigned int *data)
0e8db97a 614{
6bd65164 615 struct pci1710_private *devpriv = dev->private;
3e5cf6d4
HS
616 unsigned int chan = CR_CHAN(insn->chanspec);
617 unsigned int range = CR_RANGE(insn->chanspec);
1e85c1ea 618 unsigned int val;
3e5cf6d4 619 int i;
0e8db97a 620
3e5cf6d4
HS
621 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
622 val |= (range << (chan << 1));
623 if (val != devpriv->da_ranges) {
624 outb(val, dev->iobase + PCI1720_RANGE);
625 devpriv->da_ranges = val;
0e8db97a
MD
626 }
627
3e5cf6d4
HS
628 val = s->readback[chan];
629 for (i = 0; i < insn->n; i++) {
630 val = data[i];
1e85c1ea 631 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
3e5cf6d4 632 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
0e8db97a
MD
633 }
634
e4623cee 635 s->readback[chan] = val;
0e8db97a 636
3e5cf6d4 637 return insn->n;
0e8db97a
MD
638}
639
4fa7bbec
HS
640static int pci171x_ai_cancel(struct comedi_device *dev,
641 struct comedi_subdevice *s)
642{
4fa7bbec
HS
643 struct pci1710_private *devpriv = dev->private;
644
e4451eeb
HS
645 devpriv->CntrlReg &= Control_CNT0;
646 devpriv->CntrlReg |= Control_SW;
647 /* reset any operations */
648 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
649 pci171x_start_pacer(dev, false);
650 outb(0, dev->iobase + PCI171x_CLRFIFO);
651 outb(0, dev->iobase + PCI171x_CLRINT);
4fa7bbec 652
4fa7bbec
HS
653 return 0;
654}
655
e2d8c43b
HS
656static void pci1710_handle_every_sample(struct comedi_device *dev,
657 struct comedi_subdevice *s)
0e8db97a 658{
aaf483b1 659 struct comedi_cmd *cmd = &s->async->cmd;
16c7eb60
HS
660 unsigned int status;
661 unsigned int val;
662 int ret;
0e8db97a 663
16c7eb60
HS
664 status = inw(dev->iobase + PCI171x_STATUS);
665 if (status & Status_FE) {
666 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
3e6cb74f 667 s->async->events |= COMEDI_CB_ERROR;
0e8db97a
MD
668 return;
669 }
16c7eb60 670 if (status & Status_FF) {
96a1f91a 671 dev_dbg(dev->class_dev,
16c7eb60 672 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
3e6cb74f 673 s->async->events |= COMEDI_CB_ERROR;
0e8db97a
MD
674 return;
675 }
676
2696fb57 677 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
0e8db97a 678
0e8db97a 679 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
7fd2dae2 680 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
16c7eb60 681 if (ret) {
3e6cb74f 682 s->async->events |= COMEDI_CB_ERROR;
16c7eb60
HS
683 break;
684 }
0e8db97a 685
a9c3a015 686 comedi_buf_write_samples(s, &val, 1);
16c7eb60 687
f831de10
HS
688 if (cmd->stop_src == TRIG_COUNT &&
689 s->async->scans_done >= cmd->stop_arg) {
690 s->async->events |= COMEDI_CB_EOA;
691 break;
0e8db97a
MD
692 }
693 }
694
2696fb57 695 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
0e8db97a
MD
696}
697
e2d8c43b
HS
698static void pci1710_handle_fifo(struct comedi_device *dev,
699 struct comedi_subdevice *s)
0e8db97a 700{
7bd428c4 701 struct pci1710_private *devpriv = dev->private;
c0e4a8de
HS
702 struct comedi_async *async = s->async;
703 struct comedi_cmd *cmd = &async->cmd;
704 unsigned int status;
705 int i;
0e8db97a 706
c0e4a8de
HS
707 status = inw(dev->iobase + PCI171x_STATUS);
708 if (!(status & Status_FH)) {
709 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
710 async->events |= COMEDI_CB_ERROR;
0e8db97a
MD
711 return;
712 }
c0e4a8de 713 if (status & Status_FF) {
96a1f91a 714 dev_dbg(dev->class_dev,
c0e4a8de
HS
715 "A/D FIFO Full status (Fatal Error!)\n");
716 async->events |= COMEDI_CB_ERROR;
0e8db97a
MD
717 return;
718 }
719
c0e4a8de
HS
720 for (i = 0; i < devpriv->max_samples; i++) {
721 unsigned int val;
722 int ret;
0e8db97a 723
c0e4a8de
HS
724 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
725 if (ret) {
726 s->async->events |= COMEDI_CB_ERROR;
727 break;
728 }
729
730 if (!comedi_buf_write_samples(s, &val, 1))
731 break;
732
733 if (cmd->stop_src == TRIG_COUNT &&
734 async->scans_done >= cmd->stop_arg) {
735 async->events |= COMEDI_CB_EOA;
736 break;
737 }
b4720286 738 }
0e8db97a 739
c0e4a8de 740 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
0e8db97a
MD
741}
742
70265d24 743static irqreturn_t interrupt_service_pci1710(int irq, void *d)
0e8db97a 744{
71b5f4f1 745 struct comedi_device *dev = d;
6bd65164 746 struct pci1710_private *devpriv = dev->private;
5297a6ba
HS
747 struct comedi_subdevice *s;
748 struct comedi_cmd *cmd;
0e8db97a 749
2696fb57
BP
750 if (!dev->attached) /* is device attached? */
751 return IRQ_NONE; /* no, exit */
5297a6ba
HS
752
753 s = dev->read_subdev;
754 cmd = &s->async->cmd;
755
ed7dcb47
TM
756 /* is this interrupt from our board? */
757 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
2696fb57 758 return IRQ_NONE; /* no, exit */
0e8db97a 759
2696fb57 760 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
0e8db97a
MD
761 devpriv->ai_et = 0;
762 devpriv->CntrlReg &= Control_CNT0;
ed7dcb47 763 devpriv->CntrlReg |= Control_SW; /* set software trigger */
0e8db97a
MD
764 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
765 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
766 outb(0, dev->iobase + PCI171x_CLRFIFO);
767 outb(0, dev->iobase + PCI171x_CLRINT);
768 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
769 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
925ddefc 770 pci171x_start_pacer(dev, true);
0e8db97a
MD
771 return IRQ_HANDLED;
772 }
5297a6ba 773
3e609aff 774 if (cmd->flags & CMDF_WAKE_EOS)
e2d8c43b 775 pci1710_handle_every_sample(dev, s);
5297a6ba 776 else
e2d8c43b 777 pci1710_handle_fifo(dev, s);
5297a6ba 778
d61b786a
HS
779 comedi_handle_events(dev, s);
780
0e8db97a
MD
781 return IRQ_HANDLED;
782}
783
eec2f4ef 784static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
0e8db97a 785{
6bd65164 786 struct pci1710_private *devpriv = dev->private;
cd0164e6 787 struct comedi_cmd *cmd = &s->async->cmd;
0e8db97a 788
925ddefc 789 pci171x_start_pacer(dev, false);
0e8db97a 790
a65e1419
HS
791 pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
792 devpriv->saved_seglen);
0e8db97a
MD
793
794 outb(0, dev->iobase + PCI171x_CLRFIFO);
795 outb(0, dev->iobase + PCI171x_CLRINT);
796
0e8db97a 797 devpriv->CntrlReg &= Control_CNT0;
3e609aff 798 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
0e8db97a 799 devpriv->CntrlReg |= Control_ONEFH;
0e8db97a 800
73bcf01c
HS
801 devpriv->divisor1 = devpriv->next_divisor1;
802 devpriv->divisor2 = devpriv->next_divisor2;
803
33573343 804 if (cmd->convert_src == TRIG_TIMER) {
0e8db97a 805 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
33573343 806 if (cmd->start_src == TRIG_EXT) {
0e8db97a
MD
807 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
808 devpriv->CntrlReg &=
0a85b6f0 809 ~(Control_PACER | Control_ONEFH | Control_GATE);
0e8db97a
MD
810 devpriv->CntrlReg |= Control_EXT;
811 devpriv->ai_et = 1;
33573343 812 } else { /* TRIG_NOW */
0e8db97a
MD
813 devpriv->ai_et = 0;
814 }
0e8db97a 815 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
33573343 816
925ddefc
HS
817 if (cmd->start_src == TRIG_NOW)
818 pci171x_start_pacer(dev, true);
33573343 819 } else { /* TRIG_EXT */
0e8db97a
MD
820 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
821 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
0e8db97a
MD
822 }
823
0e8db97a
MD
824 return 0;
825}
826
0a85b6f0
MT
827static int pci171x_ai_cmdtest(struct comedi_device *dev,
828 struct comedi_subdevice *s,
829 struct comedi_cmd *cmd)
0e8db97a 830{
6bd65164 831 struct pci1710_private *devpriv = dev->private;
0e8db97a 832 int err = 0;
474cd8a1 833 unsigned int arg;
0e8db97a 834
27020ffe 835 /* Step 1 : check if triggers are trivially valid */
0e8db97a 836
8531fce9
HS
837 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
838 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
839 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
840 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
841 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
0e8db97a 842
f5f9a3ff 843 if (err)
0e8db97a 844 return 1;
0e8db97a 845
b7f16de6 846 /* step 2a: make sure trigger sources are unique */
0e8db97a 847
b7f16de6
HS
848 err |= cfc_check_trigger_is_unique(cmd->start_src);
849 err |= cfc_check_trigger_is_unique(cmd->convert_src);
850 err |= cfc_check_trigger_is_unique(cmd->stop_src);
0e8db97a 851
b7f16de6 852 /* step 2b: and mutually compatible */
0e8db97a 853
f5f9a3ff 854 if (err)
0e8db97a 855 return 2;
0e8db97a 856
ad23feaa 857 /* Step 3: check if arguments are trivially valid */
0e8db97a 858
ad23feaa
HS
859 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
860 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
0e8db97a 861
ad23feaa 862 if (cmd->convert_src == TRIG_TIMER)
abd2839c 863 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
ad23feaa
HS
864 else /* TRIG_FOLLOW */
865 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
0e8db97a 866
ad23feaa 867 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
0e8db97a 868
ad23feaa
HS
869 if (cmd->stop_src == TRIG_COUNT)
870 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
871 else /* TRIG_NONE */
872 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
0e8db97a 873
f5f9a3ff 874 if (err)
0e8db97a 875 return 3;
0e8db97a
MD
876
877 /* step 4: fix up any arguments */
878
879 if (cmd->convert_src == TRIG_TIMER) {
474cd8a1 880 arg = cmd->convert_arg;
576a09f0 881 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
73bcf01c
HS
882 &devpriv->next_divisor1,
883 &devpriv->next_divisor2,
474cd8a1
HS
884 &arg, cmd->flags);
885 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
0e8db97a
MD
886 }
887
f5f9a3ff 888 if (err)
0e8db97a 889 return 4;
0e8db97a 890
7cc054d0 891 /* Step 5: check channel list */
0e8db97a 892
56556577
HS
893 err |= pci171x_ai_check_chanlist(dev, s, cmd);
894
895 if (err)
7cc054d0 896 return 5;
0e8db97a 897
0e8db97a
MD
898 return 0;
899}
900
da91b269 901static int pci171x_reset(struct comedi_device *dev)
0e8db97a 902{
383fab40 903 const struct boardtype *board = dev->board_ptr;
6bd65164
HS
904 struct pci1710_private *devpriv = dev->private;
905
0e8db97a 906 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
2d323be9
SA
907 /* Software trigger, CNT0=external */
908 devpriv->CntrlReg = Control_SW | Control_CNT0;
9ab6c61b
SA
909 /* reset any operations */
910 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
2696fb57
BP
911 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
912 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
925ddefc 913 pci171x_start_pacer(dev, false);
0e8db97a 914 devpriv->da_ranges = 0;
383fab40 915 if (board->has_ao) {
1d0117ff
SA
916 /* set DACs to 0..5V */
917 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
40e0ccc9 918 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
87abf660 919 outw(0, dev->iobase + PCI171x_DA2);
0e8db97a 920 }
2696fb57
BP
921 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
922 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
923 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
0e8db97a 924
0e8db97a
MD
925 return 0;
926}
927
da91b269 928static int pci1720_reset(struct comedi_device *dev)
0e8db97a 929{
6bd65164 930 struct pci1710_private *devpriv = dev->private;
9cf7aa62
SA
931 /* set synchronous output mode */
932 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
0e8db97a 933 devpriv->da_ranges = 0xAA;
260f67cb
SA
934 /* set all ranges to +/-5V */
935 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
2696fb57 936 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
0e8db97a
MD
937 outw(0x0800, dev->iobase + PCI1720_DA1);
938 outw(0x0800, dev->iobase + PCI1720_DA2);
939 outw(0x0800, dev->iobase + PCI1720_DA3);
2696fb57 940 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
e4623cee 941
0e8db97a
MD
942 return 0;
943}
944
da91b269 945static int pci1710_reset(struct comedi_device *dev)
0e8db97a 946{
383fab40 947 const struct boardtype *board = dev->board_ptr;
6bd65164 948
e4451eeb 949 if (board->is_pci1720)
0e8db97a 950 return pci1720_reset(dev);
e4451eeb
HS
951
952 return pci171x_reset(dev);
0e8db97a
MD
953}
954
a690b7e5 955static int pci1710_auto_attach(struct comedi_device *dev,
0005fbed 956 unsigned long context)
96554c81 957{
750af5e5 958 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
383fab40 959 const struct boardtype *board = NULL;
6bd65164 960 struct pci1710_private *devpriv;
96554c81
HS
961 struct comedi_subdevice *s;
962 int ret, subdev, n_subdevices;
f62608e3 963
0005fbed 964 if (context < ARRAY_SIZE(boardtypes))
383fab40
HS
965 board = &boardtypes[context];
966 if (!board)
f62608e3 967 return -ENODEV;
383fab40
HS
968 dev->board_ptr = board;
969 dev->board_name = board->name;
96554c81 970
0bdab509 971 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
c34fa261
HS
972 if (!devpriv)
973 return -ENOMEM;
96554c81 974
818f569f 975 ret = comedi_pci_enable(dev);
5f5d1b9a
HS
976 if (ret)
977 return ret;
ad37c85c 978 dev->iobase = pci_resource_start(pcidev, 2);
0e8db97a
MD
979
980 n_subdevices = 0;
383fab40 981 if (board->n_aichan)
0e8db97a 982 n_subdevices++;
383fab40 983 if (board->has_ao)
0e8db97a 984 n_subdevices++;
383fab40 985 if (board->has_di_do)
068de2b6 986 n_subdevices += 2;
383fab40 987 if (board->has_counter)
0e8db97a
MD
988 n_subdevices++;
989
2f0b9d08 990 ret = comedi_alloc_subdevices(dev, n_subdevices);
8b6c5694 991 if (ret)
0e8db97a 992 return ret;
0e8db97a
MD
993
994 pci1710_reset(dev);
995
383fab40 996 if (board->has_irq && pcidev->irq) {
f62608e3
HS
997 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
998 IRQF_SHARED, dev->board_name, dev);
999 if (ret == 0)
1000 dev->irq = pcidev->irq;
0e8db97a
MD
1001 }
1002
0e8db97a
MD
1003 subdev = 0;
1004
383fab40 1005 if (board->n_aichan) {
5c60f867 1006 s = &dev->subdevices[subdev];
fc8e8689
HS
1007 s->type = COMEDI_SUBD_AI;
1008 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
383fab40 1009 if (board->has_diff_ai)
fc8e8689 1010 s->subdev_flags |= SDF_DIFF;
383fab40 1011 s->n_chan = board->n_aichan;
fc8e8689 1012 s->maxdata = 0x0fff;
383fab40 1013 s->range_table = board->rangelist_ai;
fc8e8689 1014 s->insn_read = pci171x_ai_insn_read;
f62608e3 1015 if (dev->irq) {
67fb892c 1016 dev->read_subdev = s;
fc8e8689
HS
1017 s->subdev_flags |= SDF_CMD_READ;
1018 s->len_chanlist = s->n_chan;
1019 s->do_cmdtest = pci171x_ai_cmdtest;
1020 s->do_cmd = pci171x_ai_cmd;
1021 s->cancel = pci171x_ai_cancel;
0e8db97a 1022 }
0e8db97a
MD
1023 subdev++;
1024 }
1025
383fab40 1026 if (board->has_ao) {
5c60f867 1027 s = &dev->subdevices[subdev];
b420eeaf
HS
1028 s->type = COMEDI_SUBD_AO;
1029 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1030 s->maxdata = 0x0fff;
e4451eeb 1031 if (board->is_pci1720) {
b420eeaf 1032 s->n_chan = 4;
7a772eea 1033 s->range_table = &pci1720_ao_range;
b420eeaf 1034 s->insn_write = pci1720_ao_insn_write;
e4451eeb 1035 } else {
b420eeaf 1036 s->n_chan = 2;
7a772eea 1037 s->range_table = &pci171x_ao_range;
b420eeaf 1038 s->insn_write = pci171x_ao_insn_write;
0e8db97a 1039 }
e4623cee
HS
1040
1041 ret = comedi_alloc_subdev_readback(s);
1042 if (ret)
1043 return ret;
1044
1045 /* initialize the readback values to match the board reset */
e4451eeb 1046 if (board->is_pci1720) {
e4623cee
HS
1047 int i;
1048
1049 for (i = 0; i < s->n_chan; i++)
1050 s->readback[i] = 0x0800;
1051 }
1052
0e8db97a
MD
1053 subdev++;
1054 }
1055
383fab40 1056 if (board->has_di_do) {
5c60f867 1057 s = &dev->subdevices[subdev];
1fbe6e91
HS
1058 s->type = COMEDI_SUBD_DI;
1059 s->subdev_flags = SDF_READABLE;
1060 s->n_chan = 16;
1061 s->maxdata = 1;
1062 s->range_table = &range_digital;
1063 s->insn_bits = pci171x_di_insn_bits;
0e8db97a 1064 subdev++;
0e8db97a 1065
5c60f867 1066 s = &dev->subdevices[subdev];
1fbe6e91
HS
1067 s->type = COMEDI_SUBD_DO;
1068 s->subdev_flags = SDF_WRITABLE;
1069 s->n_chan = 16;
1070 s->maxdata = 1;
1071 s->range_table = &range_digital;
1072 s->insn_bits = pci171x_do_insn_bits;
0e8db97a
MD
1073 subdev++;
1074 }
1075
383fab40 1076 if (board->has_counter) {
5c60f867 1077 s = &dev->subdevices[subdev];
db2c4a05
HS
1078 s->type = COMEDI_SUBD_COUNTER;
1079 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1080 s->n_chan = 1;
1081 s->maxdata = 0xffff;
1082 s->range_table = &range_unknown;
1083 s->insn_read = pci171x_counter_insn_read;
1084 s->insn_write = pci171x_counter_insn_write;
1085 s->insn_config = pci171x_counter_insn_config;
0e8db97a
MD
1086 subdev++;
1087 }
1088
7bd428c4 1089 /* max_samples is half the FIFO size (2 bytes/sample) */
383fab40 1090 devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
7bd428c4 1091
0e8db97a
MD
1092 return 0;
1093}
1094
484ecc95 1095static void pci1710_detach(struct comedi_device *dev)
0e8db97a 1096{
398e6f12
HS
1097 if (dev->iobase)
1098 pci1710_reset(dev);
aac307f9 1099 comedi_pci_detach(dev);
0e8db97a
MD
1100}
1101
958c5989
HS
1102static struct comedi_driver adv_pci1710_driver = {
1103 .driver_name = "adv_pci1710",
1104 .module = THIS_MODULE,
750af5e5 1105 .auto_attach = pci1710_auto_attach,
958c5989 1106 .detach = pci1710_detach,
958c5989
HS
1107};
1108
a690b7e5 1109static int adv_pci1710_pci_probe(struct pci_dev *dev,
b8f4ac23 1110 const struct pci_device_id *id)
727b286b 1111{
b8f4ac23
HS
1112 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1113 id->driver_data);
727b286b
AT
1114}
1115
41e043fc 1116static const struct pci_device_id adv_pci1710_pci_table[] = {
94cc409b
IA
1117 {
1118 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1119 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1120 .driver_data = BOARD_PCI1710,
1121 }, {
1122 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1123 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1124 .driver_data = BOARD_PCI1710,
1125 }, {
1126 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1127 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1128 .driver_data = BOARD_PCI1710,
1129 }, {
1130 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1131 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1132 .driver_data = BOARD_PCI1710,
1133 }, {
1134 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1135 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1136 .driver_data = BOARD_PCI1710,
1137 }, {
1138 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1139 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1140 .driver_data = BOARD_PCI1710,
1141 }, {
1142 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1143 .driver_data = BOARD_PCI1710,
1144 }, {
1145 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1146 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1147 .driver_data = BOARD_PCI1710HG,
1148 }, {
1149 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1150 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1151 .driver_data = BOARD_PCI1710HG,
1152 }, {
1153 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1154 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1155 .driver_data = BOARD_PCI1710HG,
1156 }, {
1157 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1158 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1159 .driver_data = BOARD_PCI1710HG,
1160 }, {
1161 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1162 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1163 .driver_data = BOARD_PCI1710HG,
1164 }, {
1165 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1166 .driver_data = BOARD_PCI1710HG,
1167 },
0005fbed
HS
1168 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1169 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1170 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1171 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
958c5989 1172 { 0 }
727b286b 1173};
958c5989 1174MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
727b286b 1175
958c5989
HS
1176static struct pci_driver adv_pci1710_pci_driver = {
1177 .name = "adv_pci1710",
1178 .id_table = adv_pci1710_pci_table,
1179 .probe = adv_pci1710_pci_probe,
9901a4d7 1180 .remove = comedi_pci_auto_unconfig,
958c5989
HS
1181};
1182module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
90f703d3
AT
1183
1184MODULE_AUTHOR("Comedi http://www.comedi.org");
76201d05 1185MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
90f703d3 1186MODULE_LICENSE("GPL");
This page took 1.036371 seconds and 5 git commands to generate.