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