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#include "../comedidev.h"
102
103#include <linux/ioport.h>
104#include <linux/mc146818rtc.h>
105#include <linux/delay.h>
106#include <asm/dma.h>
107
108#include "8253.h"
109
110
111
112
113
114#define boardPCL818L 0
115#define boardPCL818H 1
116#define boardPCL818HD 2
117#define boardPCL818HG 3
118#define boardPCL818 4
119#define boardPCL718 5
120
121
122#define PCLx1x_RANGE 16
123
124#define PCLx1xFIFO_RANGE 32
125
126
127#define PCL818_CLRINT 8
128
129#define PCL818_STATUS 8
130
131#define PCL818_RANGE 1
132
133#define PCL818_MUX 2
134
135#define PCL818_CONTROL 9
136
137#define PCL818_CNTENABLE 10
138
139
140#define PCL818_AD_LO 0
141
142#define PCL818_AD_HI 1
143
144#define PCL818_DA_LO 4
145#define PCL818_DA_HI 5
146
147#define PCL818_DI_LO 3
148#define PCL818_DI_HI 11
149
150#define PCL818_DO_LO 3
151#define PCL818_DO_HI 11
152
153#define PCL718_DA2_LO 6
154#define PCL718_DA2_HI 7
155
156#define PCL818_CTR0 12
157#define PCL818_CTR1 13
158#define PCL818_CTR2 14
159
160#define PCL818_CTRCTL 15
161
162
163#define PCL818_FI_ENABLE 6
164
165#define PCL818_FI_INTCLR 20
166
167#define PCL818_FI_FLUSH 25
168
169#define PCL818_FI_STATUS 25
170
171#define PCL818_FI_DATALO 23
172#define PCL818_FI_DATAHI 23
173
174
175#define INT_TYPE_AI1_INT 1
176#define INT_TYPE_AI1_DMA 2
177#define INT_TYPE_AI1_FIFO 3
178#define INT_TYPE_AI3_INT 4
179#define INT_TYPE_AI3_DMA 5
180#define INT_TYPE_AI3_FIFO 6
181#ifdef PCL818_MODE13_AO
182#define INT_TYPE_AO1_INT 7
183#define INT_TYPE_AO3_INT 8
184#endif
185
186#ifdef unused
187
188#define INT_TYPE_AI1_DMA_RTC 9
189#define INT_TYPE_AI3_DMA_RTC 10
190
191#define RTC_IRQ 8
192#define RTC_IO_EXTENT 0x10
193#endif
194
195#define MAGIC_DMA_WORD 0x5a5a
196
197static const struct comedi_lrange range_pcl818h_ai = { 9, {
198 BIP_RANGE(5),
199 BIP_RANGE(2.5),
200 BIP_RANGE(1.25),
201 BIP_RANGE(0.625),
202 UNI_RANGE(10),
203 UNI_RANGE(5),
204 UNI_RANGE(2.5),
205 UNI_RANGE(1.25),
206 BIP_RANGE(10),
207 }
208};
209
210static const struct comedi_lrange range_pcl818hg_ai = { 10, {
211 BIP_RANGE(5),
212 BIP_RANGE(0.5),
213 BIP_RANGE(0.05),
214 BIP_RANGE(0.005),
215 UNI_RANGE(10),
216 UNI_RANGE(1),
217 UNI_RANGE(0.1),
218 UNI_RANGE(0.01),
219 BIP_RANGE(10),
220 BIP_RANGE(1),
221 BIP_RANGE(0.1),
222 BIP_RANGE(0.01),
223 }
224};
225
226static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
227 BIP_RANGE(5),
228 BIP_RANGE(2.5),
229 BIP_RANGE(1.25),
230 BIP_RANGE(0.625),
231 }
232};
233
234static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
235 BIP_RANGE(10),
236 BIP_RANGE(5),
237 BIP_RANGE(2.5),
238 BIP_RANGE(1.25),
239 }
240};
241
242static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
243static const struct comedi_lrange range718_bipolar0_5 =
244 { 1, {BIP_RANGE(0.5),} };
245static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
246static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
247
248static int pcl818_attach(struct comedi_device *dev,
249 struct comedi_devconfig *it);
250static int pcl818_detach(struct comedi_device *dev);
251
252#ifdef unused
253static int RTC_lock = 0;
254static int RTC_timer_lock = 0;
255#endif
256
257struct pcl818_board {
258
259 const char *name;
260 int n_ranges;
261 int n_aichan_se;
262 int n_aichan_diff;
263 unsigned int ns_min;
264 int n_aochan;
265 int n_dichan;
266 int n_dochan;
267 const struct comedi_lrange *ai_range_type;
268 const struct comedi_lrange *ao_range_type;
269 unsigned int io_range;
270 unsigned int IRQbits;
271 unsigned int DMAbits;
272 int ai_maxdata;
273 int ao_maxdata;
274 unsigned char fifo;
275 int is_818;
276};
277
278static const struct pcl818_board boardtypes[] = {
279 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
280 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
281 0x0a, 0xfff, 0xfff, 0, 1},
282 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
283 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
284 0x0a, 0xfff, 0xfff, 0, 1},
285 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
286 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
287 0x0a, 0xfff, 0xfff, 1, 1},
288 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
289 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
290 0x0a, 0xfff, 0xfff, 1, 1},
291 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
292 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
293 0x0a, 0xfff, 0xfff, 0, 1},
294 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
295 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
296 0x0a, 0xfff, 0xfff, 0, 0},
297
298 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
299 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
300 0x0a, 0xfff, 0xfff, 0, 1 },
301};
302
303#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
304
305static struct comedi_driver driver_pcl818 = {
306 .driver_name = "pcl818",
307 .module = THIS_MODULE,
308 .attach = pcl818_attach,
309 .detach = pcl818_detach,
310 .board_name = &boardtypes[0].name,
311 .num_names = n_boardtypes,
312 .offset = sizeof(struct pcl818_board),
313};
314
315COMEDI_INITCLEANUP(driver_pcl818);
316
317struct pcl818_private {
318
319 unsigned int dma;
320 int dma_rtc;
321 unsigned int io_range;
322#ifdef unused
323 unsigned long rtc_iobase;
324 unsigned int rtc_iosize;
325 unsigned int rtc_irq;
326 struct timer_list rtc_irq_timer;
327 unsigned long rtc_freq;
328 int rtc_irq_blocked;
329#endif
330 unsigned long dmabuf[2];
331 unsigned int dmapages[2];
332 unsigned int hwdmaptr[2];
333 unsigned int hwdmasize[2];
334 unsigned int dmasamplsize;
335 unsigned int last_top_dma;
336 int next_dma_buf;
337 long dma_runs_to_end;
338 unsigned long last_dma_run;
339 unsigned char neverending_ai;
340 unsigned int ns_min;
341 int i8253_osc_base;
342 int irq_free;
343 int irq_blocked;
344 int irq_was_now_closed;
345 int ai_mode;
346 struct comedi_subdevice *last_int_sub;
347 int ai_act_scan;
348 int ai_act_chan;
349 unsigned int act_chanlist[16];
350 unsigned int act_chanlist_len;
351 unsigned int act_chanlist_pos;
352 unsigned int ai_scans;
353 unsigned int ai_n_chan;
354 unsigned int *ai_chanlist;
355 unsigned int ai_flags;
356 unsigned int ai_data_len;
357 short *ai_data;
358 unsigned int ai_timer1;
359 unsigned int ai_timer2;
360 struct comedi_subdevice *sub_ai;
361 unsigned char usefifo;
362 unsigned int ao_readback[2];
363};
364
365static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
366 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
367};
368
369#define devpriv ((struct pcl818_private *)dev->private)
370#define this_board ((const struct pcl818_board *)dev->board_ptr)
371
372
373
374
375static void setup_channel_list(struct comedi_device *dev,
376 struct comedi_subdevice *s,
377 unsigned int *chanlist, unsigned int n_chan,
378 unsigned int seglen);
379static int check_channel_list(struct comedi_device *dev,
380 struct comedi_subdevice *s,
381 unsigned int *chanlist, unsigned int n_chan);
382
383static int pcl818_ai_cancel(struct comedi_device *dev,
384 struct comedi_subdevice *s);
385static void start_pacer(struct comedi_device *dev, int mode,
386 unsigned int divisor1, unsigned int divisor2);
387
388#ifdef unused
389static int set_rtc_irq_bit(unsigned char bit);
390static void rtc_dropped_irq(unsigned long data);
391static int rtc_setfreq_irq(int freq);
392#endif
393
394
395
396
397
398static int pcl818_ai_insn_read(struct comedi_device *dev,
399 struct comedi_subdevice *s,
400 struct comedi_insn *insn, unsigned int *data)
401{
402 int n;
403 int timeout;
404
405
406 outb(0, dev->iobase + PCL818_CONTROL);
407
408
409 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
410
411
412 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
413
414 for (n = 0; n < insn->n; n++) {
415
416
417 outb(0, dev->iobase + PCL818_CLRINT);
418
419
420 outb(0, dev->iobase + PCL818_AD_LO);
421
422 timeout = 100;
423 while (timeout--) {
424 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
425 goto conv_finish;
426 udelay(1);
427 }
428 comedi_error(dev, "A/D insn timeout");
429
430 outb(0, dev->iobase + PCL818_CLRINT);
431 return -EIO;
432
433conv_finish:
434 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
435 (inb(dev->iobase + PCL818_AD_LO) >> 4));
436 }
437
438 return n;
439}
440
441
442
443
444
445
446static int pcl818_ao_insn_read(struct comedi_device *dev,
447 struct comedi_subdevice *s,
448 struct comedi_insn *insn, unsigned int *data)
449{
450 int n;
451 int chan = CR_CHAN(insn->chanspec);
452
453 for (n = 0; n < insn->n; n++) {
454 data[n] = devpriv->ao_readback[chan];
455 }
456
457 return n;
458}
459
460static int pcl818_ao_insn_write(struct comedi_device *dev,
461 struct comedi_subdevice *s,
462 struct comedi_insn *insn, unsigned int *data)
463{
464 int n;
465 int chan = CR_CHAN(insn->chanspec);
466
467 for (n = 0; n < insn->n; n++) {
468 devpriv->ao_readback[chan] = data[n];
469 outb((data[n] & 0x000f) << 4, dev->iobase +
470 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
471 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
472 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
473 }
474
475 return n;
476}
477
478
479
480
481
482
483
484static int pcl818_di_insn_bits(struct comedi_device *dev,
485 struct comedi_subdevice *s,
486 struct comedi_insn *insn, unsigned int *data)
487{
488 if (insn->n != 2)
489 return -EINVAL;
490
491 data[1] = inb(dev->iobase + PCL818_DI_LO) |
492 (inb(dev->iobase + PCL818_DI_HI) << 8);
493
494 return 2;
495}
496
497
498
499
500
501
502
503static int pcl818_do_insn_bits(struct comedi_device *dev,
504 struct comedi_subdevice *s,
505 struct comedi_insn *insn, unsigned int *data)
506{
507 if (insn->n != 2)
508 return -EINVAL;
509
510 s->state &= ~data[0];
511 s->state |= (data[0] & data[1]);
512
513 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
514 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
515
516 data[1] = s->state;
517
518 return 2;
519}
520
521
522
523
524
525
526static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
527{
528 struct comedi_device *dev = d;
529 struct comedi_subdevice *s = dev->subdevices + 0;
530 int low;
531 int timeout = 50;
532
533 while (timeout--) {
534 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
535 goto conv_finish;
536 udelay(1);
537 }
538 outb(0, dev->iobase + PCL818_STATUS);
539 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
540 pcl818_ai_cancel(dev, s);
541 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
542 comedi_event(dev, s);
543 return IRQ_HANDLED;
544
545conv_finish:
546 low = inb(dev->iobase + PCL818_AD_LO);
547 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4)));
548 outb(0, dev->iobase + PCL818_CLRINT);
549
550 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {
551 printk
552 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
553 (low & 0xf),
554 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
555 pcl818_ai_cancel(dev, s);
556 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
557 comedi_event(dev, s);
558 return IRQ_HANDLED;
559 }
560 if (s->async->cur_chan == 0) {
561
562 devpriv->ai_act_scan--;
563 }
564
565 if (!devpriv->neverending_ai) {
566 if (devpriv->ai_act_scan == 0) {
567 pcl818_ai_cancel(dev, s);
568 s->async->events |= COMEDI_CB_EOA;
569 }
570 }
571 comedi_event(dev, s);
572 return IRQ_HANDLED;
573}
574
575
576
577
578
579static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
580{
581 struct comedi_device *dev = d;
582 struct comedi_subdevice *s = dev->subdevices + 0;
583 int i, len, bufptr;
584 unsigned long flags;
585 short *ptr;
586
587 disable_dma(devpriv->dma);
588 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
589 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) {
590 set_dma_mode(devpriv->dma, DMA_MODE_READ);
591 flags = claim_dma_lock();
592 set_dma_addr(devpriv->dma,
593 devpriv->hwdmaptr[devpriv->next_dma_buf]);
594 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
595 set_dma_count(devpriv->dma,
596 devpriv->hwdmasize[devpriv->
597 next_dma_buf]);
598 } else {
599 set_dma_count(devpriv->dma, devpriv->last_dma_run);
600 }
601 release_dma_lock(flags);
602 enable_dma(devpriv->dma);
603 }
604 printk("comedi: A/D mode1/3 IRQ \n");
605
606 devpriv->dma_runs_to_end--;
607 outb(0, dev->iobase + PCL818_CLRINT);
608 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
609
610 len = devpriv->hwdmasize[0] >> 1;
611 bufptr = 0;
612
613 for (i = 0; i < len; i++) {
614 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {
615 printk
616 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
617 (ptr[bufptr] & 0xf),
618 devpriv->act_chanlist[devpriv->act_chanlist_pos],
619 devpriv->act_chanlist_pos);
620 pcl818_ai_cancel(dev, s);
621 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
622 comedi_event(dev, s);
623 return IRQ_HANDLED;
624 }
625
626 comedi_buf_put(s->async, ptr[bufptr++] >> 4);
627
628 devpriv->act_chanlist_pos++;
629 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
630 devpriv->ai_act_scan--;
631 devpriv->act_chanlist_pos = 0;
632 }
633
634 if (!devpriv->neverending_ai)
635 if (devpriv->ai_act_scan == 0) {
636 pcl818_ai_cancel(dev, s);
637 s->async->events |= COMEDI_CB_EOA;
638 comedi_event(dev, s);
639
640 return IRQ_HANDLED;
641 }
642 }
643
644 if (len > 0)
645 comedi_event(dev, s);
646 return IRQ_HANDLED;
647}
648
649#ifdef unused
650
651
652
653
654static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
655{
656 struct comedi_device *dev = d;
657 struct comedi_subdevice *s = dev->subdevices + 0;
658 unsigned long tmp;
659 unsigned int top1, top2, i, bufptr;
660 long ofs_dats;
661 short *dmabuf = (short *)devpriv->dmabuf[0];
662
663
664 switch (devpriv->ai_mode) {
665 case INT_TYPE_AI1_DMA_RTC:
666 case INT_TYPE_AI3_DMA_RTC:
667 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
668 mod_timer(&devpriv->rtc_irq_timer,
669 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
670
671 for (i = 0; i < 10; i++) {
672 top1 = get_dma_residue(devpriv->dma);
673 top2 = get_dma_residue(devpriv->dma);
674 if (top1 == top2)
675 break;
676 }
677
678 if (top1 != top2)
679 return IRQ_HANDLED;
680 top1 = devpriv->hwdmasize[0] - top1;
681 top1 >>= 1;
682 ofs_dats = top1 - devpriv->last_top_dma;
683 if (ofs_dats < 0)
684 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
685 if (!ofs_dats)
686 return IRQ_HANDLED;
687
688 i = devpriv->last_top_dma - 1;
689 i &= (devpriv->dmasamplsize - 1);
690
691 if (dmabuf[i] != MAGIC_DMA_WORD) {
692 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
693
694 pcl818_ai_cancel(dev, s);
695 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
696 comedi_event(dev, s);
697 return IRQ_HANDLED;
698 }
699
700
701 bufptr = devpriv->last_top_dma;
702
703 for (i = 0; i < ofs_dats; i++) {
704 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {
705 printk
706 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
707 (dmabuf[bufptr] & 0xf),
708 devpriv->
709 act_chanlist[devpriv->act_chanlist_pos]);
710 pcl818_ai_cancel(dev, s);
711 s->async->events |=
712 COMEDI_CB_EOA | COMEDI_CB_ERROR;
713 comedi_event(dev, s);
714 return IRQ_HANDLED;
715 }
716
717 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4);
718 bufptr &= (devpriv->dmasamplsize - 1);
719
720 if (s->async->cur_chan == 0) {
721 devpriv->ai_act_scan--;
722 }
723
724 if (!devpriv->neverending_ai)
725 if (devpriv->ai_act_scan == 0) {
726 pcl818_ai_cancel(dev, s);
727 s->async->events |= COMEDI_CB_EOA;
728 comedi_event(dev, s);
729
730 return IRQ_HANDLED;
731 }
732 }
733
734 devpriv->last_top_dma = bufptr;
735 bufptr--;
736 bufptr &= (devpriv->dmasamplsize - 1);
737 dmabuf[bufptr] = MAGIC_DMA_WORD;
738 comedi_event(dev, s);
739
740 return IRQ_HANDLED;
741 }
742
743
744 return IRQ_HANDLED;
745}
746#endif
747
748
749
750
751
752static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
753{
754 struct comedi_device *dev = d;
755 struct comedi_subdevice *s = dev->subdevices + 0;
756 int i, len, lo;
757
758 outb(0, dev->iobase + PCL818_FI_INTCLR);
759
760 lo = inb(dev->iobase + PCL818_FI_STATUS);
761
762 if (lo & 4) {
763 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
764 pcl818_ai_cancel(dev, s);
765 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
766 comedi_event(dev, s);
767 return IRQ_HANDLED;
768 }
769
770 if (lo & 1) {
771 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
772 pcl818_ai_cancel(dev, s);
773 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
774 comedi_event(dev, s);
775 return IRQ_HANDLED;
776 }
777
778 if (lo & 2) {
779 len = 512;
780 } else {
781 len = 0;
782 }
783
784 for (i = 0; i < len; i++) {
785 lo = inb(dev->iobase + PCL818_FI_DATALO);
786 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) {
787 printk
788 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
789 (lo & 0xf),
790 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
791 pcl818_ai_cancel(dev, s);
792 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
793 comedi_event(dev, s);
794 return IRQ_HANDLED;
795 }
796
797 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4));
798
799 if (s->async->cur_chan == 0) {
800 devpriv->ai_act_scan--;
801 }
802
803 if (!devpriv->neverending_ai)
804 if (devpriv->ai_act_scan == 0) {
805 pcl818_ai_cancel(dev, s);
806 s->async->events |= COMEDI_CB_EOA;
807 comedi_event(dev, s);
808 return IRQ_HANDLED;
809 }
810 }
811
812 if (len > 0)
813 comedi_event(dev, s);
814 return IRQ_HANDLED;
815}
816
817
818
819
820
821static irqreturn_t interrupt_pcl818(int irq, void *d)
822{
823 struct comedi_device *dev = d;
824
825 if (!dev->attached) {
826 comedi_error(dev, "premature interrupt");
827 return IRQ_HANDLED;
828 }
829
830
831 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
832 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
833 devpriv->ai_act_scan > 0)) &&
834 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
835 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
836
837
838
839
840
841 struct comedi_subdevice *s = dev->subdevices + 0;
842 devpriv->ai_act_scan = 0;
843 devpriv->neverending_ai = 0;
844 pcl818_ai_cancel(dev, s);
845 }
846
847 outb(0, dev->iobase + PCL818_CLRINT);
848
849 return IRQ_HANDLED;
850 }
851
852 switch (devpriv->ai_mode) {
853 case INT_TYPE_AI1_DMA:
854 case INT_TYPE_AI3_DMA:
855 return interrupt_pcl818_ai_mode13_dma(irq, d);
856 case INT_TYPE_AI1_INT:
857 case INT_TYPE_AI3_INT:
858 return interrupt_pcl818_ai_mode13_int(irq, d);
859 case INT_TYPE_AI1_FIFO:
860 case INT_TYPE_AI3_FIFO:
861 return interrupt_pcl818_ai_mode13_fifo(irq, d);
862#ifdef PCL818_MODE13_AO
863 case INT_TYPE_AO1_INT:
864 case INT_TYPE_AO3_INT:
865 return interrupt_pcl818_ao_mode13_int(irq, d);
866#endif
867 default:
868 break;
869 }
870
871 outb(0, dev->iobase + PCL818_CLRINT);
872
873 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
874 || (!devpriv->ai_mode)) {
875 comedi_error(dev, "bad IRQ!");
876 return IRQ_NONE;
877 }
878
879 comedi_error(dev, "IRQ from unknow source!");
880 return IRQ_NONE;
881}
882
883
884
885
886
887static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
888 struct comedi_subdevice *s)
889{
890 unsigned int flags;
891 unsigned int bytes;
892
893 printk("mode13dma_int, mode: %d\n", mode);
894 disable_dma(devpriv->dma);
895 bytes = devpriv->hwdmasize[0];
896 if (!devpriv->neverending_ai) {
897 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short);
898 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0];
899 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
900 devpriv->dma_runs_to_end--;
901 if (devpriv->dma_runs_to_end >= 0)
902 bytes = devpriv->hwdmasize[0];
903 }
904
905 devpriv->next_dma_buf = 0;
906 set_dma_mode(devpriv->dma, DMA_MODE_READ);
907 flags = claim_dma_lock();
908 clear_dma_ff(devpriv->dma);
909 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
910 set_dma_count(devpriv->dma, bytes);
911 release_dma_lock(flags);
912 enable_dma(devpriv->dma);
913
914 if (mode == 1) {
915 devpriv->ai_mode = INT_TYPE_AI1_DMA;
916 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
917 } else {
918 devpriv->ai_mode = INT_TYPE_AI3_DMA;
919 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
920 };
921}
922
923#ifdef unused
924
925
926
927
928static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
929 struct comedi_subdevice *s)
930{
931 unsigned int flags;
932 short *pole;
933
934 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
935 flags = claim_dma_lock();
936 clear_dma_ff(devpriv->dma);
937 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
938 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
939 release_dma_lock(flags);
940 enable_dma(devpriv->dma);
941 devpriv->last_top_dma = 0;
942 pole = (short *)devpriv->dmabuf[0];
943 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
944 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
945#ifdef unused
946 devpriv->rtc_freq = rtc_setfreq_irq(2048);
947 devpriv->rtc_irq_timer.expires =
948 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
949 devpriv->rtc_irq_timer.data = (unsigned long)dev;
950 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
951
952 add_timer(&devpriv->rtc_irq_timer);
953#endif
954
955 if (mode == 1) {
956 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
957 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
958 } else {
959 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
960 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
961 };
962}
963#endif
964
965
966
967
968
969static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
970 struct comedi_subdevice *s)
971{
972 struct comedi_cmd *cmd = &s->async->cmd;
973 int divisor1, divisor2;
974 unsigned int seglen;
975
976 printk("pcl818_ai_cmd_mode()\n");
977 if ((!dev->irq) && (!devpriv->dma_rtc)) {
978 comedi_error(dev, "IRQ not defined!");
979 return -EINVAL;
980 }
981
982 if (devpriv->irq_blocked)
983 return -EBUSY;
984
985 start_pacer(dev, -1, 0, 0);
986
987 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
988 devpriv->ai_n_chan);
989 if (seglen < 1)
990 return -EINVAL;
991 setup_channel_list(dev, s, devpriv->ai_chanlist,
992 devpriv->ai_n_chan, seglen);
993
994 udelay(1);
995
996 devpriv->ai_act_scan = devpriv->ai_scans;
997 devpriv->ai_act_chan = 0;
998 devpriv->irq_blocked = 1;
999 devpriv->irq_was_now_closed = 0;
1000 devpriv->neverending_ai = 0;
1001 devpriv->act_chanlist_pos = 0;
1002 devpriv->dma_runs_to_end = 0;
1003
1004 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
1005 devpriv->neverending_ai = 1;
1006
1007 if (mode == 1) {
1008 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1009 &divisor2, &cmd->convert_arg,
1010 TRIG_ROUND_NEAREST);
1011 if (divisor1 == 1) {
1012 divisor1 = 2;
1013 divisor2 /= 2;
1014 }
1015 if (divisor2 == 1) {
1016 divisor2 = 2;
1017 divisor1 /= 2;
1018 }
1019 }
1020
1021 outb(0, dev->iobase + PCL818_CNTENABLE);
1022
1023 switch (devpriv->dma) {
1024 case 1:
1025 case 3:
1026 if (devpriv->dma_rtc == 0) {
1027 pcl818_ai_mode13dma_int(mode, dev, s);
1028 }
1029#ifdef unused
1030 else {
1031 pcl818_ai_mode13dma_rtc(mode, dev, s);
1032 }
1033#else
1034 else {
1035 return -EINVAL;
1036 }
1037#endif
1038 break;
1039 case 0:
1040 if (!devpriv->usefifo) {
1041
1042
1043 if (mode == 1) {
1044 devpriv->ai_mode = INT_TYPE_AI1_INT;
1045
1046 outb(0x83 | (dev->irq << 4),
1047 dev->iobase + PCL818_CONTROL);
1048 } else {
1049 devpriv->ai_mode = INT_TYPE_AI3_INT;
1050
1051 outb(0x82 | (dev->irq << 4),
1052 dev->iobase + PCL818_CONTROL);
1053 }
1054 } else {
1055
1056
1057 outb(1, dev->iobase + PCL818_FI_ENABLE);
1058 if (mode == 1) {
1059 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1060
1061 outb(0x03, dev->iobase + PCL818_CONTROL);
1062 } else {
1063 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1064 outb(0x02, dev->iobase + PCL818_CONTROL);
1065 }
1066 }
1067 }
1068
1069 start_pacer(dev, mode, divisor1, divisor2);
1070
1071#ifdef unused
1072 switch (devpriv->ai_mode) {
1073 case INT_TYPE_AI1_DMA_RTC:
1074 case INT_TYPE_AI3_DMA_RTC:
1075 set_rtc_irq_bit(1);
1076 break;
1077 }
1078#endif
1079 printk("pcl818_ai_cmd_mode() end\n");
1080 return 0;
1081}
1082
1083#ifdef unused
1084
1085
1086
1087
1088#ifdef PCL818_MODE13_AO
1089static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1090 struct comedi_subdevice *s, comedi_trig * it)
1091{
1092 int divisor1, divisor2;
1093
1094 if (!dev->irq) {
1095 comedi_error(dev, "IRQ not defined!");
1096 return -EINVAL;
1097 }
1098
1099 if (devpriv->irq_blocked)
1100 return -EBUSY;
1101
1102 start_pacer(dev, -1, 0, 0);
1103
1104 devpriv->int13_act_scan = it->n;
1105 devpriv->int13_act_chan = 0;
1106 devpriv->irq_blocked = 1;
1107 devpriv->irq_was_now_closed = 0;
1108 devpriv->neverending_ai = 0;
1109 devpriv->act_chanlist_pos = 0;
1110
1111 if (mode == 1) {
1112 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1113 &divisor2, &it->trigvar,
1114 TRIG_ROUND_NEAREST);
1115 if (divisor1 == 1) {
1116 divisor1 = 2;
1117 divisor2 /= 2;
1118 }
1119 if (divisor2 == 1) {
1120 divisor2 = 2;
1121 divisor1 /= 2;
1122 }
1123 }
1124
1125 outb(0, dev->iobase + PCL818_CNTENABLE);
1126 if (mode == 1) {
1127 devpriv->int818_mode = INT_TYPE_AO1_INT;
1128 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
1129 } else {
1130 devpriv->int818_mode = INT_TYPE_AO3_INT;
1131 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
1132 };
1133
1134 start_pacer(dev, mode, divisor1, divisor2);
1135
1136 return 0;
1137}
1138
1139
1140
1141
1142
1143static int pcl818_ao_mode1(struct comedi_device *dev,
1144 struct comedi_subdevice *s, comedi_trig * it)
1145{
1146 return pcl818_ao_mode13(1, dev, s, it);
1147}
1148
1149
1150
1151
1152
1153static int pcl818_ao_mode3(struct comedi_device *dev,
1154 struct comedi_subdevice *s, comedi_trig * it)
1155{
1156 return pcl818_ao_mode13(3, dev, s, it);
1157}
1158#endif
1159#endif
1160
1161
1162
1163
1164
1165static void start_pacer(struct comedi_device *dev, int mode,
1166 unsigned int divisor1, unsigned int divisor2)
1167{
1168 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1169 outb(0x74, dev->iobase + PCL818_CTRCTL);
1170 udelay(1);
1171
1172 if (mode == 1) {
1173 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1174 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1175 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1176 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1177 }
1178}
1179
1180
1181
1182
1183
1184
1185static int check_channel_list(struct comedi_device *dev,
1186 struct comedi_subdevice *s,
1187 unsigned int *chanlist, unsigned int n_chan)
1188{
1189 unsigned int chansegment[16];
1190 unsigned int i, nowmustbechan, seglen, segpos;
1191
1192
1193 if (n_chan < 1) {
1194 comedi_error(dev, "range/channel list is empty!");
1195 return 0;
1196 }
1197
1198 if (n_chan > 1) {
1199
1200 chansegment[0] = chanlist[0];
1201
1202 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1203
1204
1205
1206
1207
1208
1209 if (chanlist[0] == chanlist[i])
1210 break;
1211 nowmustbechan =
1212 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1213 if (nowmustbechan != CR_CHAN(chanlist[i])) {
1214 printk
1215 ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1216 dev->minor, i, CR_CHAN(chanlist[i]),
1217 nowmustbechan, CR_CHAN(chanlist[0]));
1218 return 0;
1219 }
1220
1221 chansegment[i] = chanlist[i];
1222 }
1223
1224
1225 for (i = 0, segpos = 0; i < n_chan; i++) {
1226
1227 if (chanlist[i] != chansegment[i % seglen]) {
1228 printk
1229 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1230 dev->minor, i, CR_CHAN(chansegment[i]),
1231 CR_RANGE(chansegment[i]),
1232 CR_AREF(chansegment[i]),
1233 CR_CHAN(chanlist[i % seglen]),
1234 CR_RANGE(chanlist[i % seglen]),
1235 CR_AREF(chansegment[i % seglen]));
1236 return 0;
1237 }
1238 }
1239 } else {
1240 seglen = 1;
1241 }
1242 printk("check_channel_list: seglen %d\n", seglen);
1243 return seglen;
1244}
1245
1246static void setup_channel_list(struct comedi_device *dev,
1247 struct comedi_subdevice *s,
1248 unsigned int *chanlist, unsigned int n_chan,
1249 unsigned int seglen)
1250{
1251 int i;
1252
1253 devpriv->act_chanlist_len = seglen;
1254 devpriv->act_chanlist_pos = 0;
1255
1256 for (i = 0; i < seglen; i++) {
1257 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1258 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX);
1259 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE);
1260 }
1261
1262 udelay(1);
1263
1264
1265 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1266 1] << 4),
1267 dev->iobase + PCL818_MUX);
1268}
1269
1270
1271
1272
1273
1274static int check_single_ended(unsigned int port)
1275{
1276 if (inb(port + PCL818_STATUS) & 0x20) {
1277 return 1;
1278 } else {
1279 return 0;
1280 }
1281}
1282
1283
1284
1285
1286static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1287 struct comedi_cmd *cmd)
1288{
1289 int err = 0;
1290 int tmp, divisor1, divisor2;
1291
1292
1293
1294 tmp = cmd->start_src;
1295 cmd->start_src &= TRIG_NOW;
1296 if (!cmd->start_src || tmp != cmd->start_src)
1297 err++;
1298
1299 tmp = cmd->scan_begin_src;
1300 cmd->scan_begin_src &= TRIG_FOLLOW;
1301 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1302 err++;
1303
1304 tmp = cmd->convert_src;
1305 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1306 if (!cmd->convert_src || tmp != cmd->convert_src)
1307 err++;
1308
1309 tmp = cmd->scan_end_src;
1310 cmd->scan_end_src &= TRIG_COUNT;
1311 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1312 err++;
1313
1314 tmp = cmd->stop_src;
1315 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1316 if (!cmd->stop_src || tmp != cmd->stop_src)
1317 err++;
1318
1319 if (err) {
1320 return 1;
1321 }
1322
1323
1324
1325 if (cmd->start_src != TRIG_NOW) {
1326 cmd->start_src = TRIG_NOW;
1327 err++;
1328 }
1329 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1330 cmd->scan_begin_src = TRIG_FOLLOW;
1331 err++;
1332 }
1333 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1334 err++;
1335
1336 if (cmd->scan_end_src != TRIG_COUNT) {
1337 cmd->scan_end_src = TRIG_COUNT;
1338 err++;
1339 }
1340
1341 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1342 err++;
1343
1344 if (err) {
1345 return 2;
1346 }
1347
1348
1349
1350 if (cmd->start_arg != 0) {
1351 cmd->start_arg = 0;
1352 err++;
1353 }
1354
1355 if (cmd->scan_begin_arg != 0) {
1356 cmd->scan_begin_arg = 0;
1357 err++;
1358 }
1359
1360 if (cmd->convert_src == TRIG_TIMER) {
1361 if (cmd->convert_arg < this_board->ns_min) {
1362 cmd->convert_arg = this_board->ns_min;
1363 err++;
1364 }
1365 } else {
1366 if (cmd->convert_arg != 0) {
1367 cmd->convert_arg = 0;
1368 err++;
1369 }
1370 }
1371
1372 if (!cmd->chanlist_len) {
1373 cmd->chanlist_len = 1;
1374 err++;
1375 }
1376 if (cmd->chanlist_len > s->n_chan) {
1377 cmd->chanlist_len = s->n_chan;
1378 err++;
1379 }
1380 if (cmd->scan_end_arg != cmd->chanlist_len) {
1381 cmd->scan_end_arg = cmd->chanlist_len;
1382 err++;
1383 }
1384 if (cmd->stop_src == TRIG_COUNT) {
1385 if (!cmd->stop_arg) {
1386 cmd->stop_arg = 1;
1387 err++;
1388 }
1389 } else {
1390 if (cmd->stop_arg != 0) {
1391 cmd->stop_arg = 0;
1392 err++;
1393 }
1394 }
1395
1396 if (err) {
1397 return 3;
1398 }
1399
1400
1401
1402 if (cmd->convert_src == TRIG_TIMER) {
1403 tmp = cmd->convert_arg;
1404 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1405 &divisor2, &cmd->convert_arg,
1406 cmd->flags & TRIG_ROUND_MASK);
1407 if (cmd->convert_arg < this_board->ns_min)
1408 cmd->convert_arg = this_board->ns_min;
1409 if (tmp != cmd->convert_arg)
1410 err++;
1411 }
1412
1413 if (err) {
1414 return 4;
1415 }
1416
1417
1418
1419 if (cmd->chanlist) {
1420 if (!check_channel_list(dev, s, cmd->chanlist,
1421 cmd->chanlist_len))
1422 return 5;
1423 }
1424
1425 return 0;
1426}
1427
1428
1429
1430
1431static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1432{
1433 struct comedi_cmd *cmd = &s->async->cmd;
1434 int retval;
1435
1436 printk("pcl818_ai_cmd()\n");
1437 devpriv->ai_n_chan = cmd->chanlist_len;
1438 devpriv->ai_chanlist = cmd->chanlist;
1439 devpriv->ai_flags = cmd->flags;
1440 devpriv->ai_data_len = s->async->prealloc_bufsz;
1441 devpriv->ai_data = s->async->prealloc_buf;
1442 devpriv->ai_timer1 = 0;
1443 devpriv->ai_timer2 = 0;
1444
1445 if (cmd->stop_src == TRIG_COUNT) {
1446 devpriv->ai_scans = cmd->stop_arg;
1447 } else {
1448 devpriv->ai_scans = 0;
1449 }
1450
1451 if (cmd->scan_begin_src == TRIG_FOLLOW) {
1452 if (cmd->convert_src == TRIG_TIMER) {
1453 devpriv->ai_timer1 = cmd->convert_arg;
1454 retval = pcl818_ai_cmd_mode(1, dev, s);
1455 printk("pcl818_ai_cmd() end\n");
1456 return retval;
1457 }
1458 if (cmd->convert_src == TRIG_EXT) {
1459 return pcl818_ai_cmd_mode(3, dev, s);
1460 }
1461 }
1462
1463 return -1;
1464}
1465
1466
1467
1468
1469
1470static int pcl818_ai_cancel(struct comedi_device *dev,
1471 struct comedi_subdevice *s)
1472{
1473 if (devpriv->irq_blocked > 0) {
1474 printk("pcl818_ai_cancel()\n");
1475 devpriv->irq_was_now_closed = 1;
1476
1477 switch (devpriv->ai_mode) {
1478#ifdef unused
1479 case INT_TYPE_AI1_DMA_RTC:
1480 case INT_TYPE_AI3_DMA_RTC:
1481 set_rtc_irq_bit(0);
1482 del_timer(&devpriv->rtc_irq_timer);
1483#endif
1484 case INT_TYPE_AI1_DMA:
1485 case INT_TYPE_AI3_DMA:
1486 if (devpriv->neverending_ai ||
1487 (!devpriv->neverending_ai &&
1488 devpriv->ai_act_scan > 0)) {
1489
1490 goto end;
1491 }
1492 disable_dma(devpriv->dma);
1493 case INT_TYPE_AI1_INT:
1494 case INT_TYPE_AI3_INT:
1495 case INT_TYPE_AI1_FIFO:
1496 case INT_TYPE_AI3_FIFO:
1497#ifdef PCL818_MODE13_AO
1498 case INT_TYPE_AO1_INT:
1499 case INT_TYPE_AO3_INT:
1500#endif
1501 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL);
1502 udelay(1);
1503 start_pacer(dev, -1, 0, 0);
1504 outb(0, dev->iobase + PCL818_AD_LO);
1505 inb(dev->iobase + PCL818_AD_LO);
1506 inb(dev->iobase + PCL818_AD_HI);
1507 outb(0, dev->iobase + PCL818_CLRINT);
1508 outb(0, dev->iobase + PCL818_CONTROL);
1509 if (devpriv->usefifo) {
1510 outb(0, dev->iobase + PCL818_FI_INTCLR);
1511 outb(0, dev->iobase + PCL818_FI_FLUSH);
1512 outb(0, dev->iobase + PCL818_FI_ENABLE);
1513 }
1514 devpriv->irq_blocked = 0;
1515 devpriv->last_int_sub = s;
1516 devpriv->neverending_ai = 0;
1517 devpriv->ai_mode = 0;
1518 devpriv->irq_was_now_closed = 0;
1519 break;
1520 }
1521 }
1522
1523end:
1524 printk("pcl818_ai_cancel() end\n");
1525 return 0;
1526}
1527
1528
1529
1530
1531
1532static int pcl818_check(unsigned long iobase)
1533{
1534 outb(0x00, iobase + PCL818_MUX);
1535 udelay(1);
1536 if (inb(iobase + PCL818_MUX) != 0x00)
1537 return 1;
1538 outb(0x55, iobase + PCL818_MUX);
1539 udelay(1);
1540 if (inb(iobase + PCL818_MUX) != 0x55)
1541 return 1;
1542 outb(0x00, iobase + PCL818_MUX);
1543 udelay(1);
1544 outb(0x18, iobase + PCL818_CONTROL);
1545 udelay(1);
1546 if (inb(iobase + PCL818_CONTROL) != 0x18)
1547 return 1;
1548 return 0;
1549}
1550
1551
1552
1553
1554
1555static void pcl818_reset(struct comedi_device *dev)
1556{
1557 if (devpriv->usefifo) {
1558 outb(0, dev->iobase + PCL818_FI_INTCLR);
1559 outb(0, dev->iobase + PCL818_FI_FLUSH);
1560 outb(0, dev->iobase + PCL818_FI_ENABLE);
1561 }
1562 outb(0, dev->iobase + PCL818_DA_LO);
1563 outb(0, dev->iobase + PCL818_DA_HI);
1564 udelay(1);
1565 outb(0, dev->iobase + PCL818_DO_HI);
1566 outb(0, dev->iobase + PCL818_DO_LO);
1567 udelay(1);
1568 outb(0, dev->iobase + PCL818_CONTROL);
1569 outb(0, dev->iobase + PCL818_CNTENABLE);
1570 outb(0, dev->iobase + PCL818_MUX);
1571 outb(0, dev->iobase + PCL818_CLRINT);
1572 outb(0xb0, dev->iobase + PCL818_CTRCTL);
1573 outb(0x70, dev->iobase + PCL818_CTRCTL);
1574 outb(0x30, dev->iobase + PCL818_CTRCTL);
1575 if (this_board->is_818) {
1576 outb(0, dev->iobase + PCL818_RANGE);
1577 } else {
1578 outb(0, dev->iobase + PCL718_DA2_LO);
1579 outb(0, dev->iobase + PCL718_DA2_HI);
1580 }
1581}
1582
1583#ifdef unused
1584
1585
1586
1587
1588static int set_rtc_irq_bit(unsigned char bit)
1589{
1590 unsigned char val;
1591 unsigned long flags;
1592
1593 if (bit == 1) {
1594 RTC_timer_lock++;
1595 if (RTC_timer_lock > 1)
1596 return 0;
1597 } else {
1598 RTC_timer_lock--;
1599 if (RTC_timer_lock < 0)
1600 RTC_timer_lock = 0;
1601 if (RTC_timer_lock > 0)
1602 return 0;
1603 }
1604
1605 save_flags(flags);
1606 cli();
1607 val = CMOS_READ(RTC_CONTROL);
1608 if (bit) {
1609 val |= RTC_PIE;
1610 } else {
1611 val &= ~RTC_PIE;
1612 }
1613 CMOS_WRITE(val, RTC_CONTROL);
1614 CMOS_READ(RTC_INTR_FLAGS);
1615 restore_flags(flags);
1616 return 0;
1617}
1618
1619
1620
1621
1622
1623static void rtc_dropped_irq(unsigned long data)
1624{
1625 struct comedi_device *dev = (void *)data;
1626 unsigned long flags, tmp;
1627
1628 switch (devpriv->int818_mode) {
1629 case INT_TYPE_AI1_DMA_RTC:
1630 case INT_TYPE_AI3_DMA_RTC:
1631 mod_timer(&devpriv->rtc_irq_timer,
1632 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1633 save_flags(flags);
1634 cli();
1635 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
1636 restore_flags(flags);
1637 break;
1638 };
1639}
1640
1641
1642
1643
1644
1645static int rtc_setfreq_irq(int freq)
1646{
1647 int tmp = 0;
1648 int rtc_freq;
1649 unsigned char val;
1650 unsigned long flags;
1651
1652 if (freq < 2)
1653 freq = 2;
1654 if (freq > 8192)
1655 freq = 8192;
1656
1657 while (freq > (1 << tmp))
1658 tmp++;
1659
1660 rtc_freq = 1 << tmp;
1661
1662 save_flags(flags);
1663 cli();
1664 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1665 val |= (16 - tmp);
1666 CMOS_WRITE(val, RTC_FREQ_SELECT);
1667 restore_flags(flags);
1668 return rtc_freq;
1669}
1670#endif
1671
1672
1673
1674
1675
1676static void free_resources(struct comedi_device *dev)
1677{
1678
1679 if (dev->private) {
1680 pcl818_ai_cancel(dev, devpriv->sub_ai);
1681 pcl818_reset(dev);
1682 if (devpriv->dma)
1683 free_dma(devpriv->dma);
1684 if (devpriv->dmabuf[0])
1685 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1686 if (devpriv->dmabuf[1])
1687 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1688#ifdef unused
1689 if (devpriv->rtc_irq)
1690 free_irq(devpriv->rtc_irq, dev);
1691 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1692 if (devpriv->rtc_iobase)
1693 release_region(devpriv->rtc_iobase,
1694 devpriv->rtc_iosize);
1695 }
1696 if (devpriv->dma_rtc)
1697 RTC_lock--;
1698#endif
1699 }
1700
1701 if (dev->irq)
1702 free_irq(dev->irq, dev);
1703 if (dev->iobase)
1704 release_region(dev->iobase, devpriv->io_range);
1705
1706}
1707
1708
1709
1710
1711
1712
1713
1714static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1715{
1716 int ret;
1717 unsigned long iobase;
1718 unsigned int irq;
1719 int dma;
1720 unsigned long pages;
1721 struct comedi_subdevice *s;
1722
1723 ret = alloc_private(dev, sizeof(struct pcl818_private));
1724 if (ret < 0)
1725 return ret;
1726
1727
1728 iobase = it->options[0];
1729 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1730 dev->minor, this_board->name, iobase);
1731 devpriv->io_range = this_board->io_range;
1732 if ((this_board->fifo) && (it->options[2] == -1)) {
1733 devpriv->io_range = PCLx1xFIFO_RANGE;
1734 devpriv->usefifo = 1;
1735 }
1736 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1737 printk("I/O port conflict\n");
1738 return -EIO;
1739 }
1740
1741 dev->iobase = iobase;
1742
1743 if (pcl818_check(iobase)) {
1744 printk(", I can't detect board. FAIL!\n");
1745 return -EIO;
1746 }
1747
1748
1749 dev->board_name = this_board->name;
1750
1751 irq = 0;
1752 if (this_board->IRQbits != 0) {
1753 irq = it->options[1];
1754 if (irq) {
1755 if (((1 << irq) & this_board->IRQbits) == 0) {
1756 printk
1757 (", IRQ %u is out of allowed range, DISABLING IT",
1758 irq);
1759 irq = 0;
1760 } else {
1761 if (request_irq
1762 (irq, interrupt_pcl818, 0, "pcl818", dev)) {
1763 printk
1764 (", unable to allocate IRQ %u, DISABLING IT",
1765 irq);
1766 irq = 0;
1767 } else {
1768 printk(", irq=%u", irq);
1769 }
1770 }
1771 }
1772 }
1773
1774 dev->irq = irq;
1775 if (irq) {
1776 devpriv->irq_free = 1;
1777 }
1778 else {
1779 devpriv->irq_free = 0;
1780 }
1781 devpriv->irq_blocked = 0;
1782 devpriv->ai_mode = 0;
1783
1784#ifdef unused
1785
1786 devpriv->dma_rtc = 0;
1787 if (it->options[2] > 0) {
1788 if (RTC_lock == 0) {
1789 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1790 "pcl818 (RTC)"))
1791 goto no_rtc;
1792 }
1793 devpriv->rtc_iobase = RTC_PORT(0);
1794 devpriv->rtc_iosize = RTC_IO_EXTENT;
1795 RTC_lock++;
1796 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
1797 "pcl818 DMA (RTC)", dev)) {
1798 devpriv->dma_rtc = 1;
1799 devpriv->rtc_irq = RTC_IRQ;
1800 printk(", dma_irq=%u", devpriv->rtc_irq);
1801 } else {
1802 RTC_lock--;
1803 if (RTC_lock == 0) {
1804 if (devpriv->rtc_iobase)
1805 release_region(devpriv->rtc_iobase,
1806 devpriv->rtc_iosize);
1807 }
1808 devpriv->rtc_iobase = 0;
1809 devpriv->rtc_iosize = 0;
1810 }
1811 }
1812
1813no_rtc:
1814#endif
1815
1816 dma = 0;
1817 devpriv->dma = dma;
1818 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1819 goto no_dma;
1820 if (this_board->DMAbits != 0) {
1821 dma = it->options[2];
1822 if (dma < 1)
1823 goto no_dma;
1824 if (((1 << dma) & this_board->DMAbits) == 0) {
1825 printk(", DMA is out of allowed range, FAIL!\n");
1826 return -EINVAL;
1827 }
1828 ret = request_dma(dma, "pcl818");
1829 if (ret) {
1830 printk(", unable to allocate DMA %u, FAIL!\n", dma);
1831 return -EBUSY;
1832 }
1833 devpriv->dma = dma;
1834 printk(", dma=%u", dma);
1835 pages = 2;
1836 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1837 if (!devpriv->dmabuf[0]) {
1838 printk(", unable to allocate DMA buffer, FAIL!\n");
1839
1840 return -EBUSY;
1841 }
1842 devpriv->dmapages[0] = pages;
1843 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1844 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1845
1846 if (devpriv->dma_rtc == 0) {
1847 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1848 if (!devpriv->dmabuf[1]) {
1849 printk
1850 (", unable to allocate DMA buffer, FAIL!\n");
1851 return -EBUSY;
1852 }
1853 devpriv->dmapages[1] = pages;
1854 devpriv->hwdmaptr[1] =
1855 virt_to_bus((void *)devpriv->dmabuf[1]);
1856 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1857 }
1858 }
1859
1860no_dma:
1861
1862 ret = alloc_subdevices(dev, 4);
1863 if (ret < 0)
1864 return ret;
1865
1866 s = dev->subdevices + 0;
1867 if (!this_board->n_aichan_se) {
1868 s->type = COMEDI_SUBD_UNUSED;
1869 } else {
1870 s->type = COMEDI_SUBD_AI;
1871 devpriv->sub_ai = s;
1872 s->subdev_flags = SDF_READABLE;
1873 if (check_single_ended(dev->iobase)) {
1874 s->n_chan = this_board->n_aichan_se;
1875 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1876 printk(", %dchans S.E. DAC", s->n_chan);
1877 } else {
1878 s->n_chan = this_board->n_aichan_diff;
1879 s->subdev_flags |= SDF_DIFF;
1880 printk(", %dchans DIFF DAC", s->n_chan);
1881 }
1882 s->maxdata = this_board->ai_maxdata;
1883 s->len_chanlist = s->n_chan;
1884 s->range_table = this_board->ai_range_type;
1885 s->cancel = pcl818_ai_cancel;
1886 s->insn_read = pcl818_ai_insn_read;
1887 if ((irq) || (devpriv->dma_rtc)) {
1888 dev->read_subdev = s;
1889 s->subdev_flags |= SDF_CMD_READ;
1890 s->do_cmdtest = ai_cmdtest;
1891 s->do_cmd = ai_cmd;
1892 }
1893 if (this_board->is_818) {
1894 if ((it->options[4] == 1) || (it->options[4] == 10))
1895 s->range_table = &range_pcl818l_h_ai;
1896 } else {
1897 switch (it->options[4]) {
1898 case 0:
1899 s->range_table = &range_bipolar10;
1900 break;
1901 case 1:
1902 s->range_table = &range_bipolar5;
1903 break;
1904 case 2:
1905 s->range_table = &range_bipolar2_5;
1906 break;
1907 case 3:
1908 s->range_table = &range718_bipolar1;
1909 break;
1910 case 4:
1911 s->range_table = &range718_bipolar0_5;
1912 break;
1913 case 6:
1914 s->range_table = &range_unipolar10;
1915 break;
1916 case 7:
1917 s->range_table = &range_unipolar5;
1918 break;
1919 case 8:
1920 s->range_table = &range718_unipolar2;
1921 break;
1922 case 9:
1923 s->range_table = &range718_unipolar1;
1924 break;
1925 default:
1926 s->range_table = &range_unknown;
1927 break;
1928 }
1929 }
1930 }
1931
1932 s = dev->subdevices + 1;
1933 if (!this_board->n_aochan) {
1934 s->type = COMEDI_SUBD_UNUSED;
1935 } else {
1936 s->type = COMEDI_SUBD_AO;
1937 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1938 s->n_chan = this_board->n_aochan;
1939 s->maxdata = this_board->ao_maxdata;
1940 s->len_chanlist = this_board->n_aochan;
1941 s->range_table = this_board->ao_range_type;
1942 s->insn_read = pcl818_ao_insn_read;
1943 s->insn_write = pcl818_ao_insn_write;
1944#ifdef unused
1945#ifdef PCL818_MODE13_AO
1946 if (irq) {
1947 s->trig[1] = pcl818_ao_mode1;
1948 s->trig[3] = pcl818_ao_mode3;
1949 }
1950#endif
1951#endif
1952 if (this_board->is_818) {
1953 if ((it->options[4] == 1) || (it->options[4] == 10))
1954 s->range_table = &range_unipolar10;
1955 if (it->options[4] == 2)
1956 s->range_table = &range_unknown;
1957 } else {
1958 if ((it->options[5] == 1) || (it->options[5] == 10))
1959 s->range_table = &range_unipolar10;
1960 if (it->options[5] == 2)
1961 s->range_table = &range_unknown;
1962 }
1963 }
1964
1965 s = dev->subdevices + 2;
1966 if (!this_board->n_dichan) {
1967 s->type = COMEDI_SUBD_UNUSED;
1968 } else {
1969 s->type = COMEDI_SUBD_DI;
1970 s->subdev_flags = SDF_READABLE;
1971 s->n_chan = this_board->n_dichan;
1972 s->maxdata = 1;
1973 s->len_chanlist = this_board->n_dichan;
1974 s->range_table = &range_digital;
1975 s->insn_bits = pcl818_di_insn_bits;
1976 }
1977
1978 s = dev->subdevices + 3;
1979 if (!this_board->n_dochan) {
1980 s->type = COMEDI_SUBD_UNUSED;
1981 } else {
1982 s->type = COMEDI_SUBD_DO;
1983 s->subdev_flags = SDF_WRITABLE;
1984 s->n_chan = this_board->n_dochan;
1985 s->maxdata = 1;
1986 s->len_chanlist = this_board->n_dochan;
1987 s->range_table = &range_digital;
1988 s->insn_bits = pcl818_do_insn_bits;
1989 }
1990
1991
1992 if ((it->options[3] == 0) || (it->options[3] == 10)) {
1993 devpriv->i8253_osc_base = 100;
1994 } else {
1995 devpriv->i8253_osc_base = 1000;
1996 }
1997
1998
1999 devpriv->ns_min = this_board->ns_min;
2000
2001 if (!this_board->is_818) {
2002 if ((it->options[6] == 1) || (it->options[6] == 100))
2003 devpriv->ns_min = 10000;
2004 }
2005
2006 pcl818_reset(dev);
2007
2008 printk("\n");
2009
2010 return 0;
2011}
2012
2013
2014
2015
2016
2017static int pcl818_detach(struct comedi_device *dev)
2018{
2019
2020 free_resources(dev);
2021 return 0;
2022}
2023