1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111#include <linux/interrupt.h>
112#include <linux/gfp.h>
113#include "../comedidev.h"
114
115#include <linux/delay.h>
116#include <linux/ioport.h>
117#include <linux/io.h>
118#include <asm/dma.h>
119
120#include "8253.h"
121
122
123#undef PCL812_EXTDEBUG
124
125
126#define boardPCL812PG 0
127#define boardPCL813B 1
128#define boardPCL812 2
129#define boardPCL813 3
130#define boardISO813 5
131#define boardACL8113 6
132#define boardACL8112 7
133#define boardACL8216 8
134#define boardA821 9
135
136#define PCLx1x_IORANGE 16
137
138#define PCL812_CTR0 0
139#define PCL812_CTR1 1
140#define PCL812_CTR2 2
141#define PCL812_CTRCTL 3
142#define PCL812_AD_LO 4
143#define PCL812_DA1_LO 4
144#define PCL812_AD_HI 5
145#define PCL812_DA1_HI 5
146#define PCL812_DA2_LO 6
147#define PCL812_DI_LO 6
148#define PCL812_DA2_HI 7
149#define PCL812_DI_HI 7
150#define PCL812_CLRINT 8
151#define PCL812_GAIN 9
152#define PCL812_MUX 10
153#define PCL812_MODE 11
154#define PCL812_CNTENABLE 10
155#define PCL812_SOFTTRIG 12
156#define PCL812_DO_LO 13
157#define PCL812_DO_HI 14
158
159#define PCL812_DRDY 0x10
160
161#define ACL8216_STATUS 8
162
163#define ACL8216_DRDY 0x20
164
165#define MAX_CHANLIST_LEN 256
166
167static const struct comedi_lrange range_pcl812pg_ai = { 5, {
168 BIP_RANGE(5),
169 BIP_RANGE(2.5),
170 BIP_RANGE(1.25),
171 BIP_RANGE(0.625),
172 BIP_RANGE(0.3125),
173 }
174};
175
176static const struct comedi_lrange range_pcl812pg2_ai = { 5, {
177 BIP_RANGE(10),
178 BIP_RANGE(5),
179 BIP_RANGE(2.5),
180 BIP_RANGE(1.25),
181 BIP_RANGE(0.625),
182 }
183};
184
185static const struct comedi_lrange range812_bipolar1_25 = { 1, {
186 BIP_RANGE(1.25),
187 }
188};
189
190static const struct comedi_lrange range812_bipolar0_625 = { 1, {
191 BIP_RANGE
192 (0.625),
193 }
194};
195
196static const struct comedi_lrange range812_bipolar0_3125 = { 1, {
197 BIP_RANGE
198 (0.3125),
199 }
200};
201
202static const struct comedi_lrange range_pcl813b_ai = { 4, {
203 BIP_RANGE(5),
204 BIP_RANGE(2.5),
205 BIP_RANGE(1.25),
206 BIP_RANGE(0.625),
207 }
208};
209
210static const struct comedi_lrange range_pcl813b2_ai = { 4, {
211 UNI_RANGE(10),
212 UNI_RANGE(5),
213 UNI_RANGE(2.5),
214 UNI_RANGE(1.25),
215 }
216};
217
218static const struct comedi_lrange range_iso813_1_ai = { 5, {
219 BIP_RANGE(5),
220 BIP_RANGE(2.5),
221 BIP_RANGE(1.25),
222 BIP_RANGE(0.625),
223 BIP_RANGE(0.3125),
224 }
225};
226
227static const struct comedi_lrange range_iso813_1_2_ai = { 5, {
228 UNI_RANGE(10),
229 UNI_RANGE(5),
230 UNI_RANGE(2.5),
231 UNI_RANGE(1.25),
232 UNI_RANGE(0.625),
233 }
234};
235
236static const struct comedi_lrange range_iso813_2_ai = { 4, {
237 BIP_RANGE(5),
238 BIP_RANGE(2.5),
239 BIP_RANGE(1.25),
240 BIP_RANGE(0.625),
241 }
242};
243
244static const struct comedi_lrange range_iso813_2_2_ai = { 4, {
245 UNI_RANGE(10),
246 UNI_RANGE(5),
247 UNI_RANGE(2.5),
248 UNI_RANGE(1.25),
249 }
250};
251
252static const struct comedi_lrange range_acl8113_1_ai = { 4, {
253 BIP_RANGE(5),
254 BIP_RANGE(2.5),
255 BIP_RANGE(1.25),
256 BIP_RANGE(0.625),
257 }
258};
259
260static const struct comedi_lrange range_acl8113_1_2_ai = { 4, {
261 UNI_RANGE(10),
262 UNI_RANGE(5),
263 UNI_RANGE(2.5),
264 UNI_RANGE(1.25),
265 }
266};
267
268static const struct comedi_lrange range_acl8113_2_ai = { 3, {
269 BIP_RANGE(5),
270 BIP_RANGE(2.5),
271 BIP_RANGE(1.25),
272 }
273};
274
275static const struct comedi_lrange range_acl8113_2_2_ai = { 3, {
276 UNI_RANGE(10),
277 UNI_RANGE(5),
278 UNI_RANGE(2.5),
279 }
280};
281
282static const struct comedi_lrange range_acl8112dg_ai = { 9, {
283 BIP_RANGE(5),
284 BIP_RANGE(2.5),
285 BIP_RANGE(1.25),
286 BIP_RANGE(0.625),
287 UNI_RANGE(10),
288 UNI_RANGE(5),
289 UNI_RANGE(2.5),
290 UNI_RANGE(1.25),
291 BIP_RANGE(10),
292 }
293};
294
295static const struct comedi_lrange range_acl8112hg_ai = { 12, {
296 BIP_RANGE(5),
297 BIP_RANGE(0.5),
298 BIP_RANGE(0.05),
299 BIP_RANGE(0.005),
300 UNI_RANGE(10),
301 UNI_RANGE(1),
302 UNI_RANGE(0.1),
303 UNI_RANGE(0.01),
304 BIP_RANGE(10),
305 BIP_RANGE(1),
306 BIP_RANGE(0.1),
307 BIP_RANGE(0.01),
308 }
309};
310
311static const struct comedi_lrange range_a821pgh_ai = { 4, {
312 BIP_RANGE(5),
313 BIP_RANGE(0.5),
314 BIP_RANGE(0.05),
315 BIP_RANGE(0.005),
316 }
317};
318
319struct pcl812_board {
320
321 const char *name;
322 int board_type;
323 int n_aichan;
324 int n_aichan_diff;
325 int n_aochan;
326 int n_dichan;
327 int n_dochan;
328 int ai_maxdata;
329 unsigned int ai_ns_min;
330 unsigned int i8254_osc_base;
331 const struct comedi_lrange *rangelist_ai;
332 const struct comedi_lrange *rangelist_ao;
333 unsigned int IRQbits;
334 unsigned char DMAbits;
335 unsigned char io_range;
336 unsigned char haveMPC508;
337};
338
339#define this_board ((const struct pcl812_board *)dev->board_ptr)
340
341struct pcl812_private {
342
343 unsigned char valid;
344 unsigned char dma;
345 unsigned char use_diff;
346 unsigned char use_MPC;
347 unsigned char use_ext_trg;
348 unsigned char range_correction;
349 unsigned char old_chan_reg;
350 unsigned char old_gain_reg;
351 unsigned char mode_reg_int;
352 unsigned char ai_neverending;
353 unsigned char ai_eos;
354 unsigned char ai_dma;
355 unsigned int ai_poll_ptr;
356 unsigned int ai_scans;
357 unsigned int ai_act_scan;
358 unsigned int ai_chanlist[MAX_CHANLIST_LEN];
359 unsigned int ai_n_chan;
360 unsigned int ai_flags;
361 unsigned int ai_data_len;
362 short *ai_data;
363 unsigned int ai_is16b;
364 unsigned long dmabuf[2];
365 unsigned int dmapages[2];
366 unsigned int hwdmaptr[2];
367 unsigned int hwdmasize[2];
368 unsigned int dmabytestomove[2];
369 int next_dma_buf;
370 unsigned int dma_runs_to_end;
371 unsigned int last_dma_run;
372 unsigned int max_812_ai_mode0_rangewait;
373 unsigned int ao_readback[2];
374};
375
376#define devpriv ((struct pcl812_private *)dev->private)
377
378
379
380
381static void start_pacer(struct comedi_device *dev, int mode,
382 unsigned int divisor1, unsigned int divisor2);
383static void setup_range_channel(struct comedi_device *dev,
384 struct comedi_subdevice *s,
385 unsigned int rangechan, char wait);
386static int pcl812_ai_cancel(struct comedi_device *dev,
387 struct comedi_subdevice *s);
388
389
390
391static int pcl812_ai_insn_read(struct comedi_device *dev,
392 struct comedi_subdevice *s,
393 struct comedi_insn *insn, unsigned int *data)
394{
395 int n;
396 int timeout, hi;
397
398
399 outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE);
400
401 setup_range_channel(dev, s, insn->chanspec, 1);
402 for (n = 0; n < insn->n; n++) {
403
404 outb(255, dev->iobase + PCL812_SOFTTRIG);
405 udelay(5);
406 timeout = 50;
407 while (timeout--) {
408 hi = inb(dev->iobase + PCL812_AD_HI);
409 if (!(hi & PCL812_DRDY))
410 goto conv_finish;
411 udelay(1);
412 }
413 printk
414 ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
415 dev->minor, dev->board_name, dev->iobase);
416 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
417 return -ETIME;
418
419conv_finish:
420 data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO);
421 }
422 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
423 return n;
424}
425
426
427
428
429static int acl8216_ai_insn_read(struct comedi_device *dev,
430 struct comedi_subdevice *s,
431 struct comedi_insn *insn, unsigned int *data)
432{
433 int n;
434 int timeout;
435
436
437 outb(1, dev->iobase + PCL812_MODE);
438
439 setup_range_channel(dev, s, insn->chanspec, 1);
440 for (n = 0; n < insn->n; n++) {
441
442 outb(255, dev->iobase + PCL812_SOFTTRIG);
443 udelay(5);
444 timeout = 50;
445 while (timeout--) {
446 if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY))
447 goto conv_finish;
448 udelay(1);
449 }
450 printk
451 ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
452 dev->minor, dev->board_name, dev->iobase);
453 outb(0, dev->iobase + PCL812_MODE);
454 return -ETIME;
455
456conv_finish:
457 data[n] =
458 (inb(dev->iobase +
459 PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO);
460 }
461 outb(0, dev->iobase + PCL812_MODE);
462 return n;
463}
464
465
466
467
468static int pcl812_ao_insn_write(struct comedi_device *dev,
469 struct comedi_subdevice *s,
470 struct comedi_insn *insn, unsigned int *data)
471{
472 int chan = CR_CHAN(insn->chanspec);
473 int i;
474
475 for (i = 0; i < insn->n; i++) {
476 outb((data[i] & 0xff),
477 dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO));
478 outb((data[i] >> 8) & 0x0f,
479 dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI));
480 devpriv->ao_readback[chan] = data[i];
481 }
482
483 return i;
484}
485
486
487
488
489static int pcl812_ao_insn_read(struct comedi_device *dev,
490 struct comedi_subdevice *s,
491 struct comedi_insn *insn, unsigned int *data)
492{
493 int chan = CR_CHAN(insn->chanspec);
494 int i;
495
496 for (i = 0; i < insn->n; i++)
497 data[i] = devpriv->ao_readback[chan];
498
499 return i;
500}
501
502
503
504
505static int pcl812_di_insn_bits(struct comedi_device *dev,
506 struct comedi_subdevice *s,
507 struct comedi_insn *insn, unsigned int *data)
508{
509 if (insn->n != 2)
510 return -EINVAL;
511
512 data[1] = inb(dev->iobase + PCL812_DI_LO);
513 data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8;
514
515 return 2;
516}
517
518
519
520
521static int pcl812_do_insn_bits(struct comedi_device *dev,
522 struct comedi_subdevice *s,
523 struct comedi_insn *insn, unsigned int *data)
524{
525 if (insn->n != 2)
526 return -EINVAL;
527
528 if (data[0]) {
529 s->state &= ~data[0];
530 s->state |= data[0] & data[1];
531 outb(s->state & 0xff, dev->iobase + PCL812_DO_LO);
532 outb((s->state >> 8), dev->iobase + PCL812_DO_HI);
533 }
534 data[1] = s->state;
535
536 return 2;
537}
538
539#ifdef PCL812_EXTDEBUG
540
541
542
543static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd)
544{
545 printk(KERN_INFO "pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
546 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
547 printk(KERN_INFO "pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
548 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
549 printk(KERN_INFO "pcl812 e=%d stopsrc=%x scanend=%x\n", e,
550 cmd->stop_src, cmd->scan_end_src);
551 printk(KERN_INFO "pcl812 e=%d stoparg=%d scanendarg=%d "
552 "chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg,
553 cmd->chanlist_len);
554}
555#endif
556
557
558
559
560static int pcl812_ai_cmdtest(struct comedi_device *dev,
561 struct comedi_subdevice *s, struct comedi_cmd *cmd)
562{
563 int err = 0;
564 int tmp, divisor1, divisor2;
565
566#ifdef PCL812_EXTDEBUG
567 printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n");
568 pcl812_cmdtest_out(-1, cmd);
569#endif
570
571
572 tmp = cmd->start_src;
573 cmd->start_src &= TRIG_NOW;
574 if (!cmd->start_src || tmp != cmd->start_src)
575 err++;
576
577 tmp = cmd->scan_begin_src;
578 cmd->scan_begin_src &= TRIG_FOLLOW;
579 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
580 err++;
581
582 tmp = cmd->convert_src;
583 if (devpriv->use_ext_trg)
584 cmd->convert_src &= TRIG_EXT;
585 else
586 cmd->convert_src &= TRIG_TIMER;
587
588 if (!cmd->convert_src || tmp != cmd->convert_src)
589 err++;
590
591 tmp = cmd->scan_end_src;
592 cmd->scan_end_src &= TRIG_COUNT;
593 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
594 err++;
595
596 tmp = cmd->stop_src;
597 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
598 if (!cmd->stop_src || tmp != cmd->stop_src)
599 err++;
600
601 if (err) {
602#ifdef PCL812_EXTDEBUG
603 pcl812_cmdtest_out(1, cmd);
604 printk
605 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n",
606 err);
607#endif
608 return 1;
609 }
610
611
612
613
614
615
616 if (cmd->start_src != TRIG_NOW) {
617 cmd->start_src = TRIG_NOW;
618 err++;
619 }
620
621 if (cmd->scan_begin_src != TRIG_FOLLOW) {
622 cmd->scan_begin_src = TRIG_FOLLOW;
623 err++;
624 }
625
626 if (devpriv->use_ext_trg) {
627 if (cmd->convert_src != TRIG_EXT) {
628 cmd->convert_src = TRIG_EXT;
629 err++;
630 }
631 } else {
632 if (cmd->convert_src != TRIG_TIMER) {
633 cmd->convert_src = TRIG_TIMER;
634 err++;
635 }
636 }
637
638 if (cmd->scan_end_src != TRIG_COUNT) {
639 cmd->scan_end_src = TRIG_COUNT;
640 err++;
641 }
642
643 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
644 err++;
645
646 if (err) {
647#ifdef PCL812_EXTDEBUG
648 pcl812_cmdtest_out(2, cmd);
649 printk
650 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n",
651 err);
652#endif
653 return 2;
654 }
655
656
657
658 if (cmd->start_arg != 0) {
659 cmd->start_arg = 0;
660 err++;
661 }
662
663 if (cmd->scan_begin_arg != 0) {
664 cmd->scan_begin_arg = 0;
665 err++;
666 }
667
668 if (cmd->convert_src == TRIG_TIMER) {
669 if (cmd->convert_arg < this_board->ai_ns_min) {
670 cmd->convert_arg = this_board->ai_ns_min;
671 err++;
672 }
673 } else {
674 if (cmd->convert_arg != 0) {
675 cmd->convert_arg = 0;
676 err++;
677 }
678 }
679
680 if (!cmd->chanlist_len) {
681 cmd->chanlist_len = 1;
682 err++;
683 }
684 if (cmd->chanlist_len > MAX_CHANLIST_LEN) {
685 cmd->chanlist_len = this_board->n_aichan;
686 err++;
687 }
688 if (cmd->scan_end_arg != cmd->chanlist_len) {
689 cmd->scan_end_arg = cmd->chanlist_len;
690 err++;
691 }
692 if (cmd->stop_src == TRIG_COUNT) {
693 if (!cmd->stop_arg) {
694 cmd->stop_arg = 1;
695 err++;
696 }
697 } else {
698 if (cmd->stop_arg != 0) {
699 cmd->stop_arg = 0;
700 err++;
701 }
702 }
703
704 if (err) {
705#ifdef PCL812_EXTDEBUG
706 pcl812_cmdtest_out(3, cmd);
707 printk
708 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n",
709 err);
710#endif
711 return 3;
712 }
713
714
715
716 if (cmd->convert_src == TRIG_TIMER) {
717 tmp = cmd->convert_arg;
718 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
719 &divisor2, &cmd->convert_arg,
720 cmd->flags & TRIG_ROUND_MASK);
721 if (cmd->convert_arg < this_board->ai_ns_min)
722 cmd->convert_arg = this_board->ai_ns_min;
723 if (tmp != cmd->convert_arg)
724 err++;
725 }
726
727 if (err) {
728#ifdef PCL812_EXTDEBUG
729 printk
730 ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n",
731 err);
732#endif
733 return 4;
734 }
735
736 return 0;
737}
738
739
740
741
742static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
743{
744 unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes;
745 struct comedi_cmd *cmd = &s->async->cmd;
746
747#ifdef PCL812_EXTDEBUG
748 printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n");
749#endif
750
751 if (cmd->start_src != TRIG_NOW)
752 return -EINVAL;
753 if (cmd->scan_begin_src != TRIG_FOLLOW)
754 return -EINVAL;
755 if (devpriv->use_ext_trg) {
756 if (cmd->convert_src != TRIG_EXT)
757 return -EINVAL;
758 } else {
759 if (cmd->convert_src != TRIG_TIMER)
760 return -EINVAL;
761 }
762 if (cmd->scan_end_src != TRIG_COUNT)
763 return -EINVAL;
764 if (cmd->scan_end_arg != cmd->chanlist_len)
765 return -EINVAL;
766 if (cmd->chanlist_len > MAX_CHANLIST_LEN)
767 return -EINVAL;
768
769 if (cmd->convert_src == TRIG_TIMER) {
770 if (cmd->convert_arg < this_board->ai_ns_min)
771 cmd->convert_arg = this_board->ai_ns_min;
772 i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
773 &divisor1, &divisor2,
774 &cmd->convert_arg,
775 cmd->flags & TRIG_ROUND_MASK);
776 }
777
778 start_pacer(dev, -1, 0, 0);
779
780 devpriv->ai_n_chan = cmd->chanlist_len;
781 memcpy(devpriv->ai_chanlist, cmd->chanlist,
782 sizeof(unsigned int) * cmd->scan_end_arg);
783
784 setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1);
785
786 if (devpriv->dma) {
787 devpriv->ai_dma = 1;
788 for (i = 1; i < devpriv->ai_n_chan; i++)
789 if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) {
790
791 devpriv->ai_dma = 0;
792 break;
793 }
794 } else
795 devpriv->ai_dma = 0;
796
797 devpriv->ai_flags = cmd->flags;
798 devpriv->ai_data_len = s->async->prealloc_bufsz;
799 devpriv->ai_data = s->async->prealloc_buf;
800 if (cmd->stop_src == TRIG_COUNT) {
801 devpriv->ai_scans = cmd->stop_arg;
802 devpriv->ai_neverending = 0;
803 } else {
804 devpriv->ai_scans = 0;
805 devpriv->ai_neverending = 1;
806 }
807
808 devpriv->ai_act_scan = 0;
809 devpriv->ai_poll_ptr = 0;
810 s->async->cur_chan = 0;
811
812
813 if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
814 devpriv->ai_eos = 1;
815
816
817 if (devpriv->ai_n_chan == 1)
818 devpriv->ai_dma = 0;
819 }
820
821 if (devpriv->ai_dma) {
822
823 if (devpriv->ai_eos) {
824 devpriv->dmabytestomove[0] =
825 devpriv->ai_n_chan * sizeof(short);
826 devpriv->dmabytestomove[1] =
827 devpriv->ai_n_chan * sizeof(short);
828 devpriv->dma_runs_to_end = 1;
829 } else {
830 devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
831 devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
832 if (devpriv->ai_data_len < devpriv->hwdmasize[0])
833 devpriv->dmabytestomove[0] =
834 devpriv->ai_data_len;
835 if (devpriv->ai_data_len < devpriv->hwdmasize[1])
836 devpriv->dmabytestomove[1] =
837 devpriv->ai_data_len;
838 if (devpriv->ai_neverending) {
839 devpriv->dma_runs_to_end = 1;
840 } else {
841
842 bytes = devpriv->ai_n_chan *
843 devpriv->ai_scans * sizeof(short);
844
845
846 devpriv->dma_runs_to_end =
847 bytes / devpriv->dmabytestomove[0];
848
849
850 devpriv->last_dma_run =
851 bytes % devpriv->dmabytestomove[0];
852 if (devpriv->dma_runs_to_end == 0)
853 devpriv->dmabytestomove[0] =
854 devpriv->last_dma_run;
855 devpriv->dma_runs_to_end--;
856 }
857 }
858 if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) {
859 devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
860 devpriv->ai_eos = 0;
861 }
862 if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) {
863 devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
864 devpriv->ai_eos = 0;
865 }
866 devpriv->next_dma_buf = 0;
867 set_dma_mode(devpriv->dma, DMA_MODE_READ);
868 dma_flags = claim_dma_lock();
869 clear_dma_ff(devpriv->dma);
870 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
871 set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
872 release_dma_lock(dma_flags);
873 enable_dma(devpriv->dma);
874#ifdef PCL812_EXTDEBUG
875 printk
876 ("pcl812 EDBG: DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n",
877 devpriv->dma, devpriv->hwdmaptr[0],
878 devpriv->hwdmaptr[1], devpriv->dmabytestomove[0],
879 devpriv->dmabytestomove[1], devpriv->ai_eos);
880#endif
881 }
882
883 switch (cmd->convert_src) {
884 case TRIG_TIMER:
885 start_pacer(dev, 1, divisor1, divisor2);
886 break;
887 }
888
889 if (devpriv->ai_dma)
890 outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE);
891 else
892 outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE);
893
894#ifdef PCL812_EXTDEBUG
895 printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cmd(...)\n");
896#endif
897
898 return 0;
899}
900
901
902
903
904static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
905{
906 char err = 1;
907 unsigned int mask, timeout;
908 struct comedi_device *dev = d;
909 struct comedi_subdevice *s = dev->subdevices + 0;
910 unsigned int next_chan;
911
912 s->async->events = 0;
913
914 timeout = 50;
915 if (devpriv->ai_is16b) {
916 mask = 0xffff;
917 while (timeout--) {
918 if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) {
919 err = 0;
920 break;
921 }
922 udelay(1);
923 }
924 } else {
925 mask = 0x0fff;
926 while (timeout--) {
927 if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) {
928 err = 0;
929 break;
930 }
931 udelay(1);
932 }
933 }
934
935 if (err) {
936 printk
937 ("comedi%d: pcl812: (%s at 0x%lx) "
938 "A/D cmd IRQ without DRDY!\n",
939 dev->minor, dev->board_name, dev->iobase);
940 pcl812_ai_cancel(dev, s);
941 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
942 comedi_event(dev, s);
943 return IRQ_HANDLED;
944 }
945
946 comedi_buf_put(s->async,
947 ((inb(dev->iobase + PCL812_AD_HI) << 8) |
948 inb(dev->iobase + PCL812_AD_LO)) & mask);
949
950
951 next_chan = s->async->cur_chan + 1;
952 if (next_chan >= devpriv->ai_n_chan)
953 next_chan = 0;
954 if (devpriv->ai_chanlist[s->async->cur_chan] !=
955 devpriv->ai_chanlist[next_chan])
956 setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0);
957
958 outb(0, dev->iobase + PCL812_CLRINT);
959
960 s->async->cur_chan = next_chan;
961 if (next_chan == 0) {
962 devpriv->ai_act_scan++;
963 if (!(devpriv->ai_neverending))
964
965 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
966 pcl812_ai_cancel(dev, s);
967 s->async->events |= COMEDI_CB_EOA;
968 }
969 }
970
971 comedi_event(dev, s);
972 return IRQ_HANDLED;
973}
974
975
976
977
978static void transfer_from_dma_buf(struct comedi_device *dev,
979 struct comedi_subdevice *s, short *ptr,
980 unsigned int bufptr, unsigned int len)
981{
982 unsigned int i;
983
984 s->async->events = 0;
985 for (i = len; i; i--) {
986
987 comedi_buf_put(s->async, ptr[bufptr++]);
988
989 s->async->cur_chan++;
990 if (s->async->cur_chan >= devpriv->ai_n_chan) {
991 s->async->cur_chan = 0;
992 devpriv->ai_act_scan++;
993 if (!devpriv->ai_neverending)
994
995 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
996 pcl812_ai_cancel(dev, s);
997 s->async->events |= COMEDI_CB_EOA;
998 break;
999 }
1000 }
1001 }
1002
1003 comedi_event(dev, s);
1004}
1005
1006
1007
1008
1009static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
1010{
1011 struct comedi_device *dev = d;
1012 struct comedi_subdevice *s = dev->subdevices + 0;
1013 unsigned long dma_flags;
1014 int len, bufptr;
1015 short *ptr;
1016
1017#ifdef PCL812_EXTDEBUG
1018 printk(KERN_DEBUG "pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n");
1019#endif
1020 ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf];
1021 len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
1022 devpriv->ai_poll_ptr;
1023
1024 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
1025 disable_dma(devpriv->dma);
1026 set_dma_mode(devpriv->dma, DMA_MODE_READ);
1027 dma_flags = claim_dma_lock();
1028 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
1029 if (devpriv->ai_eos) {
1030 set_dma_count(devpriv->dma,
1031 devpriv->dmabytestomove[devpriv->next_dma_buf]);
1032 } else {
1033 if (devpriv->dma_runs_to_end) {
1034 set_dma_count(devpriv->dma,
1035 devpriv->dmabytestomove[devpriv->
1036 next_dma_buf]);
1037 } else {
1038 set_dma_count(devpriv->dma, devpriv->last_dma_run);
1039 }
1040 devpriv->dma_runs_to_end--;
1041 }
1042 release_dma_lock(dma_flags);
1043 enable_dma(devpriv->dma);
1044
1045 outb(0, dev->iobase + PCL812_CLRINT);
1046
1047 bufptr = devpriv->ai_poll_ptr;
1048 devpriv->ai_poll_ptr = 0;
1049
1050 transfer_from_dma_buf(dev, s, ptr, bufptr, len);
1051
1052#ifdef PCL812_EXTDEBUG
1053 printk(KERN_DEBUG "pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n");
1054#endif
1055 return IRQ_HANDLED;
1056}
1057
1058
1059
1060
1061static irqreturn_t interrupt_pcl812(int irq, void *d)
1062{
1063 struct comedi_device *dev = d;
1064
1065 if (!dev->attached) {
1066 comedi_error(dev, "spurious interrupt");
1067 return IRQ_HANDLED;
1068 }
1069 if (devpriv->ai_dma)
1070 return interrupt_pcl812_ai_dma(irq, d);
1071 else
1072 return interrupt_pcl812_ai_int(irq, d);
1073}
1074
1075
1076
1077
1078static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
1079{
1080 unsigned long flags;
1081 unsigned int top1, top2, i;
1082
1083 if (!devpriv->ai_dma)
1084 return 0;
1085
1086 spin_lock_irqsave(&dev->spinlock, flags);
1087
1088 for (i = 0; i < 10; i++) {
1089
1090 top1 = get_dma_residue(devpriv->ai_dma);
1091 top2 = get_dma_residue(devpriv->ai_dma);
1092 if (top1 == top2)
1093 break;
1094 }
1095
1096 if (top1 != top2) {
1097 spin_unlock_irqrestore(&dev->spinlock, flags);
1098 return 0;
1099 }
1100
1101 top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;
1102 top1 >>= 1;
1103 top2 = top1 - devpriv->ai_poll_ptr;
1104 if (top2 < 1) {
1105 spin_unlock_irqrestore(&dev->spinlock, flags);
1106 return 0;
1107 }
1108
1109 transfer_from_dma_buf(dev, s,
1110 (void *)devpriv->dmabuf[1 -
1111 devpriv->next_dma_buf],
1112 devpriv->ai_poll_ptr, top2);
1113
1114 devpriv->ai_poll_ptr = top1;
1115
1116 spin_unlock_irqrestore(&dev->spinlock, flags);
1117
1118 return s->async->buf_write_count - s->async->buf_read_count;
1119}
1120
1121
1122
1123
1124static void setup_range_channel(struct comedi_device *dev,
1125 struct comedi_subdevice *s,
1126 unsigned int rangechan, char wait)
1127{
1128 unsigned char chan_reg = CR_CHAN(rangechan);
1129
1130 unsigned char gain_reg = CR_RANGE(rangechan) +
1131 devpriv->range_correction;
1132
1133 if ((chan_reg == devpriv->old_chan_reg)
1134 && (gain_reg == devpriv->old_gain_reg))
1135 return;
1136
1137 devpriv->old_chan_reg = chan_reg;
1138 devpriv->old_gain_reg = gain_reg;
1139
1140 if (devpriv->use_MPC) {
1141 if (devpriv->use_diff) {
1142 chan_reg = chan_reg | 0x30;
1143 } else {
1144 if (chan_reg & 0x80)
1145
1146 chan_reg = chan_reg | 0x20;
1147 else
1148
1149 chan_reg = chan_reg | 0x10;
1150 }
1151 }
1152
1153 outb(chan_reg, dev->iobase + PCL812_MUX);
1154 outb(gain_reg, dev->iobase + PCL812_GAIN);
1155
1156
1157 if (wait)
1158
1159
1160
1161
1162 udelay(devpriv->max_812_ai_mode0_rangewait);
1163}
1164
1165
1166
1167
1168static void start_pacer(struct comedi_device *dev, int mode,
1169 unsigned int divisor1, unsigned int divisor2)
1170{
1171#ifdef PCL812_EXTDEBUG
1172 printk(KERN_DEBUG "pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode,
1173 divisor1, divisor2);
1174#endif
1175 outb(0xb4, dev->iobase + PCL812_CTRCTL);
1176 outb(0x74, dev->iobase + PCL812_CTRCTL);
1177 udelay(1);
1178
1179 if (mode == 1) {
1180 outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);
1181 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
1182 outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
1183 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
1184 }
1185#ifdef PCL812_EXTDEBUG
1186 printk(KERN_DEBUG "pcl812 EDBG: END: start_pacer(...)\n");
1187#endif
1188}
1189
1190
1191
1192
1193static void free_resources(struct comedi_device *dev)
1194{
1195
1196 if (dev->private) {
1197 if (devpriv->dmabuf[0])
1198 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1199 if (devpriv->dmabuf[1])
1200 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1201 if (devpriv->dma)
1202 free_dma(devpriv->dma);
1203 }
1204 if (dev->irq)
1205 free_irq(dev->irq, dev);
1206 if (dev->iobase)
1207 release_region(dev->iobase, this_board->io_range);
1208}
1209
1210
1211
1212
1213static int pcl812_ai_cancel(struct comedi_device *dev,
1214 struct comedi_subdevice *s)
1215{
1216#ifdef PCL812_EXTDEBUG
1217 printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n");
1218#endif
1219 if (devpriv->ai_dma)
1220 disable_dma(devpriv->dma);
1221 outb(0, dev->iobase + PCL812_CLRINT);
1222
1223 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
1224 start_pacer(dev, -1, 0, 0);
1225 outb(0, dev->iobase + PCL812_CLRINT);
1226#ifdef PCL812_EXTDEBUG
1227 printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cancel(...)\n");
1228#endif
1229 return 0;
1230}
1231
1232
1233
1234
1235static void pcl812_reset(struct comedi_device *dev)
1236{
1237#ifdef PCL812_EXTDEBUG
1238 printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_reset(...)\n");
1239#endif
1240 outb(0, dev->iobase + PCL812_MUX);
1241 outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
1242 devpriv->old_chan_reg = -1;
1243 devpriv->old_gain_reg = -1;
1244
1245 switch (this_board->board_type) {
1246 case boardPCL812PG:
1247 case boardPCL812:
1248 case boardACL8112:
1249 case boardACL8216:
1250 outb(0, dev->iobase + PCL812_DA2_LO);
1251 outb(0, dev->iobase + PCL812_DA2_HI);
1252 case boardA821:
1253 outb(0, dev->iobase + PCL812_DA1_LO);
1254 outb(0, dev->iobase + PCL812_DA1_HI);
1255 start_pacer(dev, -1, 0, 0);
1256 outb(0, dev->iobase + PCL812_DO_HI);
1257 outb(0, dev->iobase + PCL812_DO_LO);
1258 outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
1259 outb(0, dev->iobase + PCL812_CLRINT);
1260 break;
1261 case boardPCL813B:
1262 case boardPCL813:
1263 case boardISO813:
1264 case boardACL8113:
1265 udelay(5);
1266 break;
1267 }
1268 udelay(5);
1269#ifdef PCL812_EXTDEBUG
1270 printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_reset(...)\n");
1271#endif
1272}
1273
1274static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1275{
1276 int ret, subdev;
1277 unsigned long iobase;
1278 unsigned int irq;
1279 unsigned int dma;
1280 unsigned long pages;
1281 struct comedi_subdevice *s;
1282 int n_subdevices;
1283
1284 iobase = it->options[0];
1285 printk(KERN_INFO "comedi%d: pcl812: board=%s, ioport=0x%03lx",
1286 dev->minor, this_board->name, iobase);
1287
1288 if (!request_region(iobase, this_board->io_range, "pcl812")) {
1289 printk("I/O port conflict\n");
1290 return -EIO;
1291 }
1292 dev->iobase = iobase;
1293
1294 ret = alloc_private(dev, sizeof(struct pcl812_private));
1295 if (ret < 0) {
1296 free_resources(dev);
1297 return ret;
1298 }
1299
1300 dev->board_name = this_board->name;
1301
1302 irq = 0;
1303 if (this_board->IRQbits != 0) {
1304 irq = it->options[1];
1305 if (irq) {
1306 if (((1 << irq) & this_board->IRQbits) == 0) {
1307 printk
1308 (", IRQ %u is out of allowed range, "
1309 "DISABLING IT", irq);
1310 irq = 0;
1311 } else {
1312 if (request_irq
1313 (irq, interrupt_pcl812, 0, "pcl812", dev)) {
1314 printk
1315 (", unable to allocate IRQ %u, "
1316 "DISABLING IT", irq);
1317 irq = 0;
1318 } else {
1319 printk(KERN_INFO ", irq=%u", irq);
1320 }
1321 }
1322 }
1323 }
1324
1325 dev->irq = irq;
1326
1327 dma = 0;
1328 devpriv->dma = dma;
1329 if (!dev->irq)
1330 goto no_dma;
1331 if (this_board->DMAbits != 0) {
1332 dma = it->options[2];
1333 if (((1 << dma) & this_board->DMAbits) == 0) {
1334 printk(", DMA is out of allowed range, FAIL!\n");
1335 return -EINVAL;
1336 }
1337 ret = request_dma(dma, "pcl812");
1338 if (ret) {
1339 printk(KERN_ERR ", unable to allocate DMA %u, FAIL!\n",
1340 dma);
1341 return -EBUSY;
1342 }
1343 devpriv->dma = dma;
1344 printk(KERN_INFO ", dma=%u", dma);
1345 pages = 1;
1346 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1347 if (!devpriv->dmabuf[0]) {
1348 printk(", unable to allocate DMA buffer, FAIL!\n");
1349
1350
1351
1352
1353 free_resources(dev);
1354 return -EBUSY;
1355 }
1356 devpriv->dmapages[0] = pages;
1357 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1358 devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages);
1359 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1360 if (!devpriv->dmabuf[1]) {
1361 printk(KERN_ERR ", unable to allocate DMA buffer, FAIL!\n");
1362 free_resources(dev);
1363 return -EBUSY;
1364 }
1365 devpriv->dmapages[1] = pages;
1366 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1367 devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages);
1368 }
1369no_dma:
1370
1371 n_subdevices = 0;
1372 if (this_board->n_aichan > 0)
1373 n_subdevices++;
1374 if (this_board->n_aochan > 0)
1375 n_subdevices++;
1376 if (this_board->n_dichan > 0)
1377 n_subdevices++;
1378 if (this_board->n_dochan > 0)
1379 n_subdevices++;
1380
1381 ret = alloc_subdevices(dev, n_subdevices);
1382 if (ret < 0) {
1383 free_resources(dev);
1384 return ret;
1385 }
1386
1387 subdev = 0;
1388
1389
1390 if (this_board->n_aichan > 0) {
1391 s = dev->subdevices + subdev;
1392 s->type = COMEDI_SUBD_AI;
1393 s->subdev_flags = SDF_READABLE;
1394 switch (this_board->board_type) {
1395 case boardA821:
1396 if (it->options[2] == 1) {
1397 s->n_chan = this_board->n_aichan_diff;
1398 s->subdev_flags |= SDF_DIFF;
1399 devpriv->use_diff = 1;
1400 } else {
1401 s->n_chan = this_board->n_aichan;
1402 s->subdev_flags |= SDF_GROUND;
1403 }
1404 break;
1405 case boardACL8112:
1406 case boardACL8216:
1407 if (it->options[4] == 1) {
1408 s->n_chan = this_board->n_aichan_diff;
1409 s->subdev_flags |= SDF_DIFF;
1410 devpriv->use_diff = 1;
1411 } else {
1412 s->n_chan = this_board->n_aichan;
1413 s->subdev_flags |= SDF_GROUND;
1414 }
1415 break;
1416 default:
1417 s->n_chan = this_board->n_aichan;
1418 s->subdev_flags |= SDF_GROUND;
1419 break;
1420 }
1421 s->maxdata = this_board->ai_maxdata;
1422 s->len_chanlist = MAX_CHANLIST_LEN;
1423 s->range_table = this_board->rangelist_ai;
1424 if (this_board->board_type == boardACL8216)
1425 s->insn_read = acl8216_ai_insn_read;
1426 else
1427 s->insn_read = pcl812_ai_insn_read;
1428
1429 devpriv->use_MPC = this_board->haveMPC508;
1430 s->cancel = pcl812_ai_cancel;
1431 if (dev->irq) {
1432 dev->read_subdev = s;
1433 s->subdev_flags |= SDF_CMD_READ;
1434 s->do_cmdtest = pcl812_ai_cmdtest;
1435 s->do_cmd = pcl812_ai_cmd;
1436 s->poll = pcl812_ai_poll;
1437 }
1438 switch (this_board->board_type) {
1439 case boardPCL812PG:
1440 if (it->options[4] == 1)
1441 s->range_table = &range_pcl812pg2_ai;
1442 break;
1443 case boardPCL812:
1444 switch (it->options[4]) {
1445 case 0:
1446 s->range_table = &range_bipolar10;
1447 break;
1448 case 1:
1449 s->range_table = &range_bipolar5;
1450 break;
1451 case 2:
1452 s->range_table = &range_bipolar2_5;
1453 break;
1454 case 3:
1455 s->range_table = &range812_bipolar1_25;
1456 break;
1457 case 4:
1458 s->range_table = &range812_bipolar0_625;
1459 break;
1460 case 5:
1461 s->range_table = &range812_bipolar0_3125;
1462 break;
1463 default:
1464 s->range_table = &range_bipolar10;
1465 break;
1466 printk
1467 (", incorrect range number %d, changing "
1468 "to 0 (+/-10V)", it->options[4]);
1469 break;
1470 }
1471 break;
1472 break;
1473 case boardPCL813B:
1474 if (it->options[1] == 1)
1475 s->range_table = &range_pcl813b2_ai;
1476 break;
1477 case boardISO813:
1478 switch (it->options[1]) {
1479 case 0:
1480 s->range_table = &range_iso813_1_ai;
1481 break;
1482 case 1:
1483 s->range_table = &range_iso813_1_2_ai;
1484 break;
1485 case 2:
1486 s->range_table = &range_iso813_2_ai;
1487 devpriv->range_correction = 1;
1488 break;
1489 case 3:
1490 s->range_table = &range_iso813_2_2_ai;
1491 devpriv->range_correction = 1;
1492 break;
1493 default:
1494 s->range_table = &range_iso813_1_ai;
1495 break;
1496 printk
1497 (", incorrect range number %d, "
1498 "changing to 0 ", it->options[1]);
1499 break;
1500 }
1501 break;
1502 case boardACL8113:
1503 switch (it->options[1]) {
1504 case 0:
1505 s->range_table = &range_acl8113_1_ai;
1506 break;
1507 case 1:
1508 s->range_table = &range_acl8113_1_2_ai;
1509 break;
1510 case 2:
1511 s->range_table = &range_acl8113_2_ai;
1512 devpriv->range_correction = 1;
1513 break;
1514 case 3:
1515 s->range_table = &range_acl8113_2_2_ai;
1516 devpriv->range_correction = 1;
1517 break;
1518 default:
1519 s->range_table = &range_acl8113_1_ai;
1520 break;
1521 printk
1522 (", incorrect range number %d, "
1523 "changing to 0 ", it->options[1]);
1524 break;
1525 }
1526 break;
1527 }
1528 subdev++;
1529 }
1530
1531
1532 if (this_board->n_aochan > 0) {
1533 s = dev->subdevices + subdev;
1534 s->type = COMEDI_SUBD_AO;
1535 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1536 s->n_chan = this_board->n_aochan;
1537 s->maxdata = 0xfff;
1538 s->len_chanlist = 1;
1539 s->range_table = this_board->rangelist_ao;
1540 s->insn_read = pcl812_ao_insn_read;
1541 s->insn_write = pcl812_ao_insn_write;
1542 switch (this_board->board_type) {
1543 case boardA821:
1544 if (it->options[3] == 1)
1545 s->range_table = &range_unipolar10;
1546 break;
1547 case boardPCL812:
1548 case boardACL8112:
1549 case boardPCL812PG:
1550 case boardACL8216:
1551 if (it->options[5] == 1)
1552 s->range_table = &range_unipolar10;
1553 if (it->options[5] == 2)
1554 s->range_table = &range_unknown;
1555 break;
1556 }
1557 subdev++;
1558 }
1559
1560
1561 if (this_board->n_dichan > 0) {
1562 s = dev->subdevices + subdev;
1563 s->type = COMEDI_SUBD_DI;
1564 s->subdev_flags = SDF_READABLE;
1565 s->n_chan = this_board->n_dichan;
1566 s->maxdata = 1;
1567 s->len_chanlist = this_board->n_dichan;
1568 s->range_table = &range_digital;
1569 s->insn_bits = pcl812_di_insn_bits;
1570 subdev++;
1571 }
1572
1573
1574 if (this_board->n_dochan > 0) {
1575 s = dev->subdevices + subdev;
1576 s->type = COMEDI_SUBD_DO;
1577 s->subdev_flags = SDF_WRITABLE;
1578 s->n_chan = this_board->n_dochan;
1579 s->maxdata = 1;
1580 s->len_chanlist = this_board->n_dochan;
1581 s->range_table = &range_digital;
1582 s->insn_bits = pcl812_do_insn_bits;
1583 subdev++;
1584 }
1585
1586 switch (this_board->board_type) {
1587 case boardACL8216:
1588 devpriv->ai_is16b = 1;
1589 case boardPCL812PG:
1590 case boardPCL812:
1591 case boardACL8112:
1592 devpriv->max_812_ai_mode0_rangewait = 1;
1593 if (it->options[3] > 0)
1594
1595 devpriv->use_ext_trg = 1;
1596 case boardA821:
1597 devpriv->max_812_ai_mode0_rangewait = 1;
1598 devpriv->mode_reg_int = (irq << 4) & 0xf0;
1599 break;
1600 case boardPCL813B:
1601 case boardPCL813:
1602 case boardISO813:
1603 case boardACL8113:
1604
1605 devpriv->max_812_ai_mode0_rangewait = 5;
1606 break;
1607 }
1608
1609 printk(KERN_INFO "\n");
1610 devpriv->valid = 1;
1611
1612 pcl812_reset(dev);
1613
1614 return 0;
1615}
1616
1617static void pcl812_detach(struct comedi_device *dev)
1618{
1619 free_resources(dev);
1620}
1621
1622static const struct pcl812_board boardtypes[] = {
1623 {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
1624 33000, 500, &range_bipolar10, &range_unipolar5,
1625 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1626 {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
1627 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
1628 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1629 {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
1630 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
1631 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1632 {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1633 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
1634 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
1635 {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1636 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
1637 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
1638 {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
1639 10000, 500, &range_pcl813b_ai, &range_unipolar5,
1640 0x000c, 0x00, PCLx1x_IORANGE, 0},
1641 {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
1642 10000, 500, &range_pcl813b_ai, NULL,
1643 0x000c, 0x00, PCLx1x_IORANGE, 0},
1644 {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
1645 10000, 500, &range_a821pgh_ai, &range_unipolar5,
1646 0x000c, 0x00, PCLx1x_IORANGE, 0},
1647 {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1648 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
1649 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1650 {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1651 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
1652 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1653 {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1654 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
1655 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1656 {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
1657 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
1658 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1659 {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
1660 0, 0, &range_pcl813b_ai, NULL,
1661 0x0000, 0x00, PCLx1x_IORANGE, 0},
1662 {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
1663 0, 0, &range_pcl813b_ai, NULL,
1664 0x0000, 0x00, PCLx1x_IORANGE, 0},
1665 {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
1666 0, 0, &range_acl8113_1_ai, NULL,
1667 0x0000, 0x00, PCLx1x_IORANGE, 0},
1668 {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
1669 0, 0, &range_iso813_1_ai, NULL,
1670 0x0000, 0x00, PCLx1x_IORANGE, 0},
1671 {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
1672 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
1673 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
1674 {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
1675 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
1676 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
1677};
1678
1679static struct comedi_driver pcl812_driver = {
1680 .driver_name = "pcl812",
1681 .module = THIS_MODULE,
1682 .attach = pcl812_attach,
1683 .detach = pcl812_detach,
1684 .board_name = &boardtypes[0].name,
1685 .num_names = ARRAY_SIZE(boardtypes),
1686 .offset = sizeof(struct pcl812_board),
1687};
1688module_comedi_driver(pcl812_driver);
1689
1690MODULE_AUTHOR("Comedi http://www.comedi.org");
1691MODULE_DESCRIPTION("Comedi low-level driver");
1692MODULE_LICENSE("GPL");
1693