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