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#include "../comedidev.h"
36
37#include <linux/ioport.h>
38#include <linux/mc146818rtc.h>
39#include <linux/gfp.h>
40#include <linux/delay.h>
41#include <asm/dma.h>
42
43#include "8253.h"
44
45#define DEBUG(x) x
46
47
48
49#define PCLx1x_RANGE 16
50
51
52
53
54#define PCL816_CTR0 4
55#define PCL816_CTR1 5
56#define PCL816_CTR2 6
57
58#define PCL816_CTRCTL 7
59
60
61#define PCL816_RANGE 9
62
63#define PCL816_CLRINT 10
64
65#define PCL816_MUX 11
66
67#define PCL816_CONTROL 12
68
69
70#define PCL816_STATUS 13
71#define PCL816_STATUS_DRDY_MASK 0x80
72
73
74#define PCL816_AD_LO 8
75
76#define PCL816_AD_HI 9
77
78
79#define INT_TYPE_AI1_INT 1
80#define INT_TYPE_AI1_DMA 2
81#define INT_TYPE_AI3_INT 4
82#define INT_TYPE_AI3_DMA 5
83#ifdef unused
84#define INT_TYPE_AI1_DMA_RTC 9
85#define INT_TYPE_AI3_DMA_RTC 10
86
87
88#define RTC_IRQ 8
89#define RTC_IO_EXTENT 0x10
90#endif
91
92#define MAGIC_DMA_WORD 0x5a5a
93
94static const struct comedi_lrange range_pcl816 = { 8, {
95 BIP_RANGE(10),
96 BIP_RANGE(5),
97 BIP_RANGE(2.5),
98 BIP_RANGE(1.25),
99 UNI_RANGE(10),
100 UNI_RANGE(5),
101 UNI_RANGE(2.5),
102 UNI_RANGE(1.25),
103 }
104};
105
106struct pcl816_board {
107
108 const char *name;
109 int n_ranges;
110 int n_aichan;
111 unsigned int ai_ns_min;
112 int n_aochan;
113 int n_dichan;
114 int n_dochan;
115 const struct comedi_lrange *ai_range_type;
116 const struct comedi_lrange *ao_range_type;
117 unsigned int io_range;
118 unsigned int IRQbits;
119 unsigned int DMAbits;
120 int ai_maxdata;
121 int ao_maxdata;
122 int ai_chanlist;
123 int ao_chanlist;
124 int i8254_osc_base;
125};
126
127static const struct pcl816_board boardtypes[] = {
128 {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
129 &range_pcl816, PCLx1x_RANGE,
130 0x00fc,
131 0x0a,
132 0xffff,
133 0xffff,
134 1024,
135 1,
136 100},
137 {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
138 &range_pcl816, PCLx1x_RANGE,
139 0x00fc,
140 0x0a,
141 0x3fff,
142 0x3fff,
143 1024,
144 1,
145 100},
146};
147
148#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
149#define devpriv ((struct pcl816_private *)dev->private)
150#define this_board ((const struct pcl816_board *)dev->board_ptr)
151
152static int pcl816_attach(struct comedi_device *dev,
153 struct comedi_devconfig *it);
154static int pcl816_detach(struct comedi_device *dev);
155
156#ifdef unused
157static int RTC_lock = 0;
158static int RTC_timer_lock = 0;
159#endif
160
161static struct comedi_driver driver_pcl816 = {
162 .driver_name = "pcl816",
163 .module = THIS_MODULE,
164 .attach = pcl816_attach,
165 .detach = pcl816_detach,
166 .board_name = &boardtypes[0].name,
167 .num_names = n_boardtypes,
168 .offset = sizeof(struct pcl816_board),
169};
170
171static int __init driver_pcl816_init_module(void)
172{
173 return comedi_driver_register(&driver_pcl816);
174}
175
176static void __exit driver_pcl816_cleanup_module(void)
177{
178 comedi_driver_unregister(&driver_pcl816);
179}
180
181module_init(driver_pcl816_init_module);
182module_exit(driver_pcl816_cleanup_module);
183
184struct pcl816_private {
185
186 unsigned int dma;
187 int dma_rtc;
188#ifdef unused
189 unsigned long rtc_iobase;
190 unsigned int rtc_iosize;
191 unsigned int rtc_irq;
192#endif
193 unsigned long dmabuf[2];
194 unsigned int dmapages[2];
195 unsigned int hwdmaptr[2];
196 unsigned int hwdmasize[2];
197 unsigned int dmasamplsize;
198 unsigned int last_top_dma;
199 int next_dma_buf;
200 long dma_runs_to_end;
201 unsigned long last_dma_run;
202
203 unsigned int ai_scans;
204 unsigned char ai_neverending;
205 int irq_free;
206 int irq_blocked;
207#ifdef unused
208 int rtc_irq_blocked;
209#endif
210 int irq_was_now_closed;
211 int int816_mode;
212 struct comedi_subdevice *last_int_sub;
213 int ai_act_scan;
214 unsigned int ai_act_chanlist[16];
215 unsigned int ai_act_chanlist_len;
216 unsigned int ai_act_chanlist_pos;
217 unsigned int ai_n_chan;
218 unsigned int ai_poll_ptr;
219 struct comedi_subdevice *sub_ai;
220#ifdef unused
221 struct timer_list rtc_irq_timer;
222 unsigned long rtc_freq;
223#endif
224};
225
226
227
228
229static int check_channel_list(struct comedi_device *dev,
230 struct comedi_subdevice *s,
231 unsigned int *chanlist, unsigned int chanlen);
232static void setup_channel_list(struct comedi_device *dev,
233 struct comedi_subdevice *s,
234 unsigned int *chanlist, unsigned int seglen);
235static int pcl816_ai_cancel(struct comedi_device *dev,
236 struct comedi_subdevice *s);
237static void start_pacer(struct comedi_device *dev, int mode,
238 unsigned int divisor1, unsigned int divisor2);
239#ifdef unused
240static int set_rtc_irq_bit(unsigned char bit);
241#endif
242
243static int pcl816_ai_cmdtest(struct comedi_device *dev,
244 struct comedi_subdevice *s,
245 struct comedi_cmd *cmd);
246static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
247
248
249
250
251
252static int pcl816_ai_insn_read(struct comedi_device *dev,
253 struct comedi_subdevice *s,
254 struct comedi_insn *insn, unsigned int *data)
255{
256 int n;
257 int timeout;
258
259 DPRINTK("mode 0 analog input\n");
260
261 outb(0, dev->iobase + PCL816_CONTROL);
262
263 outb(0, dev->iobase + PCL816_CLRINT);
264
265
266 outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
267
268 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
269
270 for (n = 0; n < insn->n; n++) {
271
272 outb(0, dev->iobase + PCL816_AD_LO);
273
274 timeout = 100;
275 while (timeout--) {
276 if (!(inb(dev->iobase + PCL816_STATUS) &
277 PCL816_STATUS_DRDY_MASK)) {
278
279 data[n] =
280 ((inb(dev->iobase +
281 PCL816_AD_HI) << 8) |
282 (inb(dev->iobase + PCL816_AD_LO)));
283
284 outb(0, dev->iobase + PCL816_CLRINT);
285 break;
286 }
287 udelay(1);
288 }
289
290 if (!timeout) {
291 comedi_error(dev, "A/D insn timeout\n");
292 data[0] = 0;
293
294 outb(0, dev->iobase + PCL816_CLRINT);
295 return -EIO;
296 }
297
298 }
299 return n;
300}
301
302
303
304
305
306
307static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
308{
309 struct comedi_device *dev = d;
310 struct comedi_subdevice *s = dev->subdevices + 0;
311 int low, hi;
312 int timeout = 50;
313
314 while (timeout--) {
315 if (!(inb(dev->iobase + PCL816_STATUS) &
316 PCL816_STATUS_DRDY_MASK))
317 break;
318 udelay(1);
319 }
320 if (!timeout) {
321 outb(0, dev->iobase + PCL816_CLRINT);
322 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
323 pcl816_ai_cancel(dev, s);
324 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
325 comedi_event(dev, s);
326 return IRQ_HANDLED;
327
328 }
329
330
331 low = inb(dev->iobase + PCL816_AD_LO);
332 hi = inb(dev->iobase + PCL816_AD_HI);
333
334 comedi_buf_put(s->async, (hi << 8) | low);
335
336 outb(0, dev->iobase + PCL816_CLRINT);
337
338 if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
339 devpriv->ai_act_chanlist_pos = 0;
340
341 s->async->cur_chan++;
342 if (s->async->cur_chan >= devpriv->ai_n_chan) {
343 s->async->cur_chan = 0;
344 devpriv->ai_act_scan++;
345 }
346
347 if (!devpriv->ai_neverending)
348
349 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
350
351 pcl816_ai_cancel(dev, s);
352 s->async->events |= COMEDI_CB_EOA;
353 }
354 comedi_event(dev, s);
355 return IRQ_HANDLED;
356}
357
358
359
360
361
362static void transfer_from_dma_buf(struct comedi_device *dev,
363 struct comedi_subdevice *s, short *ptr,
364 unsigned int bufptr, unsigned int len)
365{
366 int i;
367
368 s->async->events = 0;
369
370 for (i = 0; i < len; i++) {
371
372 comedi_buf_put(s->async, ptr[bufptr++]);
373
374 if (++devpriv->ai_act_chanlist_pos >=
375 devpriv->ai_act_chanlist_len) {
376 devpriv->ai_act_chanlist_pos = 0;
377 }
378
379 s->async->cur_chan++;
380 if (s->async->cur_chan >= devpriv->ai_n_chan) {
381 s->async->cur_chan = 0;
382 devpriv->ai_act_scan++;
383 }
384
385 if (!devpriv->ai_neverending)
386
387 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
388 pcl816_ai_cancel(dev, s);
389 s->async->events |= COMEDI_CB_EOA;
390 s->async->events |= COMEDI_CB_BLOCK;
391 break;
392 }
393 }
394
395 comedi_event(dev, s);
396}
397
398static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
399{
400 struct comedi_device *dev = d;
401 struct comedi_subdevice *s = dev->subdevices + 0;
402 int len, bufptr, this_dma_buf;
403 unsigned long dma_flags;
404 short *ptr;
405
406 disable_dma(devpriv->dma);
407 this_dma_buf = devpriv->next_dma_buf;
408
409
410 if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
411
412 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
413 set_dma_mode(devpriv->dma, DMA_MODE_READ);
414 dma_flags = claim_dma_lock();
415
416 set_dma_addr(devpriv->dma,
417 devpriv->hwdmaptr[devpriv->next_dma_buf]);
418 if (devpriv->dma_runs_to_end) {
419 set_dma_count(devpriv->dma,
420 devpriv->hwdmasize[devpriv->
421 next_dma_buf]);
422 } else {
423 set_dma_count(devpriv->dma, devpriv->last_dma_run);
424 }
425 release_dma_lock(dma_flags);
426 enable_dma(devpriv->dma);
427 }
428
429 devpriv->dma_runs_to_end--;
430 outb(0, dev->iobase + PCL816_CLRINT);
431
432 ptr = (short *)devpriv->dmabuf[this_dma_buf];
433
434 len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
435 bufptr = devpriv->ai_poll_ptr;
436 devpriv->ai_poll_ptr = 0;
437
438 transfer_from_dma_buf(dev, s, ptr, bufptr, len);
439 return IRQ_HANDLED;
440}
441
442
443
444
445
446static irqreturn_t interrupt_pcl816(int irq, void *d)
447{
448 struct comedi_device *dev = d;
449 DPRINTK("<I>");
450
451 if (!dev->attached) {
452 comedi_error(dev, "premature interrupt");
453 return IRQ_HANDLED;
454 }
455
456 switch (devpriv->int816_mode) {
457 case INT_TYPE_AI1_DMA:
458 case INT_TYPE_AI3_DMA:
459 return interrupt_pcl816_ai_mode13_dma(irq, d);
460 case INT_TYPE_AI1_INT:
461 case INT_TYPE_AI3_INT:
462 return interrupt_pcl816_ai_mode13_int(irq, d);
463 }
464
465 outb(0, dev->iobase + PCL816_CLRINT);
466 if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) |
467 (!devpriv->int816_mode)) {
468 if (devpriv->irq_was_now_closed) {
469 devpriv->irq_was_now_closed = 0;
470
471 return IRQ_HANDLED;
472 }
473 comedi_error(dev, "bad IRQ!");
474 return IRQ_NONE;
475 }
476 comedi_error(dev, "IRQ from unknown source!");
477 return IRQ_NONE;
478}
479
480
481
482
483
484static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
485{
486 printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
487 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
488 printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
489 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
490 printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
491 cmd->stop_src, cmd->scan_end_src);
492 printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
493 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
494}
495
496
497
498
499static int pcl816_ai_cmdtest(struct comedi_device *dev,
500 struct comedi_subdevice *s, struct comedi_cmd *cmd)
501{
502 int err = 0;
503 int tmp, divisor1 = 0, divisor2 = 0;
504
505 DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
506 pcl816_cmdtest_out(-1, cmd);
507 );
508
509
510 tmp = cmd->start_src;
511 cmd->start_src &= TRIG_NOW;
512 if (!cmd->start_src || tmp != cmd->start_src)
513 err++;
514
515 tmp = cmd->scan_begin_src;
516 cmd->scan_begin_src &= TRIG_FOLLOW;
517 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
518 err++;
519
520 tmp = cmd->convert_src;
521 cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
522 if (!cmd->convert_src || tmp != cmd->convert_src)
523 err++;
524
525 tmp = cmd->scan_end_src;
526 cmd->scan_end_src &= TRIG_COUNT;
527 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
528 err++;
529
530 tmp = cmd->stop_src;
531 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
532 if (!cmd->stop_src || tmp != cmd->stop_src)
533 err++;
534
535 if (err)
536 return 1;
537
538
539
540
541
542
543
544 if (cmd->start_src != TRIG_NOW) {
545 cmd->start_src = TRIG_NOW;
546 err++;
547 }
548
549 if (cmd->scan_begin_src != TRIG_FOLLOW) {
550 cmd->scan_begin_src = TRIG_FOLLOW;
551 err++;
552 }
553
554 if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
555 cmd->convert_src = TRIG_TIMER;
556 err++;
557 }
558
559 if (cmd->scan_end_src != TRIG_COUNT) {
560 cmd->scan_end_src = TRIG_COUNT;
561 err++;
562 }
563
564 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
565 err++;
566
567 if (err)
568 return 2;
569
570
571
572 if (cmd->start_arg != 0) {
573 cmd->start_arg = 0;
574 err++;
575 }
576
577 if (cmd->scan_begin_arg != 0) {
578 cmd->scan_begin_arg = 0;
579 err++;
580 }
581 if (cmd->convert_src == TRIG_TIMER) {
582 if (cmd->convert_arg < this_board->ai_ns_min) {
583 cmd->convert_arg = this_board->ai_ns_min;
584 err++;
585 }
586 } else {
587 if (cmd->convert_arg != 0) {
588 cmd->convert_arg = 0;
589 err++;
590 }
591 }
592
593 if (cmd->scan_end_arg != cmd->chanlist_len) {
594 cmd->scan_end_arg = cmd->chanlist_len;
595 err++;
596 }
597 if (cmd->stop_src == TRIG_COUNT) {
598 if (!cmd->stop_arg) {
599 cmd->stop_arg = 1;
600 err++;
601 }
602 } else {
603 if (cmd->stop_arg != 0) {
604 cmd->stop_arg = 0;
605 err++;
606 }
607 }
608
609 if (err)
610 return 3;
611
612
613
614 if (cmd->convert_src == TRIG_TIMER) {
615 tmp = cmd->convert_arg;
616 i8253_cascade_ns_to_timer(this_board->i8254_osc_base,
617 &divisor1, &divisor2,
618 &cmd->convert_arg,
619 cmd->flags & TRIG_ROUND_MASK);
620 if (cmd->convert_arg < this_board->ai_ns_min)
621 cmd->convert_arg = this_board->ai_ns_min;
622 if (tmp != cmd->convert_arg)
623 err++;
624 }
625
626 if (err)
627 return 4;
628
629
630
631
632 if (cmd->chanlist) {
633 if (!check_channel_list(dev, s, cmd->chanlist,
634 cmd->chanlist_len))
635 return 5;
636 }
637
638 return 0;
639}
640
641static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
642{
643 unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
644 struct comedi_cmd *cmd = &s->async->cmd;
645 unsigned int seglen;
646
647 if (cmd->start_src != TRIG_NOW)
648 return -EINVAL;
649 if (cmd->scan_begin_src != TRIG_FOLLOW)
650 return -EINVAL;
651 if (cmd->scan_end_src != TRIG_COUNT)
652 return -EINVAL;
653 if (cmd->scan_end_arg != cmd->chanlist_len)
654 return -EINVAL;
655
656 if (devpriv->irq_blocked)
657 return -EBUSY;
658
659 if (cmd->convert_src == TRIG_TIMER) {
660 if (cmd->convert_arg < this_board->ai_ns_min)
661 cmd->convert_arg = this_board->ai_ns_min;
662
663 i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1,
664 &divisor2, &cmd->convert_arg,
665 cmd->flags & TRIG_ROUND_MASK);
666
667
668 if (divisor1 == 1) {
669 divisor1 = 2;
670 divisor2 /= 2;
671 }
672 if (divisor2 == 1) {
673 divisor2 = 2;
674 divisor1 /= 2;
675 }
676 }
677
678 start_pacer(dev, -1, 0, 0);
679
680 seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
681 if (seglen < 1)
682 return -EINVAL;
683 setup_channel_list(dev, s, cmd->chanlist, seglen);
684 udelay(1);
685
686 devpriv->ai_n_chan = cmd->chanlist_len;
687 devpriv->ai_act_scan = 0;
688 s->async->cur_chan = 0;
689 devpriv->irq_blocked = 1;
690 devpriv->ai_poll_ptr = 0;
691 devpriv->irq_was_now_closed = 0;
692
693 if (cmd->stop_src == TRIG_COUNT) {
694 devpriv->ai_scans = cmd->stop_arg;
695 devpriv->ai_neverending = 0;
696 } else {
697 devpriv->ai_scans = 0;
698 devpriv->ai_neverending = 1;
699 }
700
701
702 if ((cmd->flags & TRIG_WAKE_EOS)) {
703 printk(KERN_INFO
704 "pl816: You wankt WAKE_EOS but I dont want handle it");
705
706
707
708 }
709
710 if (devpriv->dma) {
711 bytes = devpriv->hwdmasize[0];
712 if (!devpriv->ai_neverending) {
713
714 bytes = s->async->cmd.chanlist_len *
715 s->async->cmd.chanlist_len *
716 sizeof(short);
717
718
719 devpriv->dma_runs_to_end = bytes /
720 devpriv->hwdmasize[0];
721
722
723 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
724 devpriv->dma_runs_to_end--;
725 if (devpriv->dma_runs_to_end >= 0)
726 bytes = devpriv->hwdmasize[0];
727 } else
728 devpriv->dma_runs_to_end = -1;
729
730 devpriv->next_dma_buf = 0;
731 set_dma_mode(devpriv->dma, DMA_MODE_READ);
732 dma_flags = claim_dma_lock();
733 clear_dma_ff(devpriv->dma);
734 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
735 set_dma_count(devpriv->dma, bytes);
736 release_dma_lock(dma_flags);
737 enable_dma(devpriv->dma);
738 }
739
740 start_pacer(dev, 1, divisor1, divisor2);
741 dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
742
743 switch (cmd->convert_src) {
744 case TRIG_TIMER:
745 devpriv->int816_mode = INT_TYPE_AI1_DMA;
746
747
748 outb(0x32, dev->iobase + PCL816_CONTROL);
749
750
751 outb(dmairq, dev->iobase + PCL816_STATUS);
752 break;
753
754 default:
755 devpriv->int816_mode = INT_TYPE_AI3_DMA;
756
757
758 outb(0x34, dev->iobase + PCL816_CONTROL);
759
760
761 outb(dmairq, dev->iobase + PCL816_STATUS);
762 break;
763 }
764
765 DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
766 return 0;
767}
768
769static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
770{
771 unsigned long flags;
772 unsigned int top1, top2, i;
773
774 if (!devpriv->dma)
775 return 0;
776
777 spin_lock_irqsave(&dev->spinlock, flags);
778
779 for (i = 0; i < 20; i++) {
780 top1 = get_dma_residue(devpriv->dma);
781 top2 = get_dma_residue(devpriv->dma);
782 if (top1 == top2)
783 break;
784 }
785 if (top1 != top2) {
786 spin_unlock_irqrestore(&dev->spinlock, flags);
787 return 0;
788 }
789
790
791 top1 = devpriv->hwdmasize[0] - top1;
792 top1 >>= 1;
793 top2 = top1 - devpriv->ai_poll_ptr;
794 if (top2 < 1) {
795 spin_unlock_irqrestore(&dev->spinlock, flags);
796 return 0;
797 }
798
799 transfer_from_dma_buf(dev, s,
800 (short *)devpriv->dmabuf[devpriv->next_dma_buf],
801 devpriv->ai_poll_ptr, top2);
802
803 devpriv->ai_poll_ptr = top1;
804 spin_unlock_irqrestore(&dev->spinlock, flags);
805
806 return s->async->buf_write_count - s->async->buf_read_count;
807}
808
809
810
811
812
813static int pcl816_ai_cancel(struct comedi_device *dev,
814 struct comedi_subdevice *s)
815{
816
817
818 if (devpriv->irq_blocked > 0) {
819 switch (devpriv->int816_mode) {
820#ifdef unused
821 case INT_TYPE_AI1_DMA_RTC:
822 case INT_TYPE_AI3_DMA_RTC:
823 set_rtc_irq_bit(0);
824 del_timer(&devpriv->rtc_irq_timer);
825#endif
826 case INT_TYPE_AI1_DMA:
827 case INT_TYPE_AI3_DMA:
828 disable_dma(devpriv->dma);
829 case INT_TYPE_AI1_INT:
830 case INT_TYPE_AI3_INT:
831 outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
832 dev->iobase + PCL816_CONTROL);
833 udelay(1);
834 outb(0, dev->iobase + PCL816_CONTROL);
835
836
837 outb(0xb0, dev->iobase + PCL816_CTRCTL);
838 outb(0x70, dev->iobase + PCL816_CTRCTL);
839 outb(0, dev->iobase + PCL816_AD_LO);
840 inb(dev->iobase + PCL816_AD_LO);
841 inb(dev->iobase + PCL816_AD_HI);
842
843
844 outb(0, dev->iobase + PCL816_CLRINT);
845
846
847 outb(0, dev->iobase + PCL816_CONTROL);
848 devpriv->irq_blocked = 0;
849 devpriv->irq_was_now_closed = devpriv->int816_mode;
850 devpriv->int816_mode = 0;
851 devpriv->last_int_sub = s;
852
853 break;
854 }
855 }
856
857 DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
858 return 0;
859}
860
861
862
863
864
865static int pcl816_check(unsigned long iobase)
866{
867 outb(0x00, iobase + PCL816_MUX);
868 udelay(1);
869 if (inb(iobase + PCL816_MUX) != 0x00)
870 return 1;
871 outb(0x55, iobase + PCL816_MUX);
872 udelay(1);
873 if (inb(iobase + PCL816_MUX) != 0x55)
874 return 1;
875 outb(0x00, iobase + PCL816_MUX);
876 udelay(1);
877 outb(0x18, iobase + PCL816_CONTROL);
878 udelay(1);
879 if (inb(iobase + PCL816_CONTROL) != 0x18)
880 return 1;
881 return 0;
882}
883
884
885
886
887
888static void pcl816_reset(struct comedi_device *dev)
889{
890
891
892
893
894
895
896 outb(0, dev->iobase + PCL816_CONTROL);
897 outb(0, dev->iobase + PCL816_MUX);
898 outb(0, dev->iobase + PCL816_CLRINT);
899 outb(0xb0, dev->iobase + PCL816_CTRCTL);
900 outb(0x70, dev->iobase + PCL816_CTRCTL);
901 outb(0x30, dev->iobase + PCL816_CTRCTL);
902 outb(0, dev->iobase + PCL816_RANGE);
903}
904
905
906
907
908
909static void
910start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
911 unsigned int divisor2)
912{
913 outb(0x32, dev->iobase + PCL816_CTRCTL);
914 outb(0xff, dev->iobase + PCL816_CTR0);
915 outb(0x00, dev->iobase + PCL816_CTR0);
916 udelay(1);
917
918
919 outb(0xb4, dev->iobase + PCL816_CTRCTL);
920
921 outb(0x74, dev->iobase + PCL816_CTRCTL);
922 udelay(1);
923
924 if (mode == 1) {
925 DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
926 divisor2);
927 outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
928 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
929 outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
930 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
931 }
932
933
934
935}
936
937
938
939
940
941
942static int
943check_channel_list(struct comedi_device *dev,
944 struct comedi_subdevice *s, unsigned int *chanlist,
945 unsigned int chanlen)
946{
947 unsigned int chansegment[16];
948 unsigned int i, nowmustbechan, seglen, segpos;
949
950
951 if (chanlen < 1) {
952 comedi_error(dev, "range/channel list is empty!");
953 return 0;
954 }
955
956 if (chanlen > 1) {
957
958 chansegment[0] = chanlist[0];
959 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
960
961 DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
962 CR_CHAN(chanlist[i]),
963 CR_RANGE(chanlist[i]));)
964
965
966 if (chanlist[0] == chanlist[i])
967 break;
968 nowmustbechan =
969 (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
970 if (nowmustbechan != CR_CHAN(chanlist[i])) {
971
972 printk(KERN_WARNING
973 "comedi%d: pcl816: channel list must "
974 "be continuous! chanlist[%i]=%d but "
975 "must be %d or %d!\n", dev->minor,
976 i, CR_CHAN(chanlist[i]), nowmustbechan,
977 CR_CHAN(chanlist[0]));
978 return 0;
979 }
980
981 chansegment[i] = chanlist[i];
982 }
983
984
985 for (i = 0, segpos = 0; i < chanlen; i++) {
986 DEBUG(printk("%d %d=%d %d\n",
987 CR_CHAN(chansegment[i % seglen]),
988 CR_RANGE(chansegment[i % seglen]),
989 CR_CHAN(chanlist[i]),
990 CR_RANGE(chanlist[i]));)
991 if (chanlist[i] != chansegment[i % seglen]) {
992 printk(KERN_WARNING
993 "comedi%d: pcl816: bad channel or range"
994 " number! chanlist[%i]=%d,%d,%d and not"
995 " %d,%d,%d!\n", dev->minor, i,
996 CR_CHAN(chansegment[i]),
997 CR_RANGE(chansegment[i]),
998 CR_AREF(chansegment[i]),
999 CR_CHAN(chanlist[i % seglen]),
1000 CR_RANGE(chanlist[i % seglen]),
1001 CR_AREF(chansegment[i % seglen]));
1002 return 0;
1003 }
1004 }
1005 } else {
1006 seglen = 1;
1007 }
1008
1009 return seglen;
1010}
1011
1012
1013
1014
1015
1016static void
1017setup_channel_list(struct comedi_device *dev,
1018 struct comedi_subdevice *s, unsigned int *chanlist,
1019 unsigned int seglen)
1020{
1021 unsigned int i;
1022
1023 devpriv->ai_act_chanlist_len = seglen;
1024 devpriv->ai_act_chanlist_pos = 0;
1025
1026 for (i = 0; i < seglen; i++) {
1027 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
1028 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
1029
1030 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
1031 }
1032
1033 udelay(1);
1034
1035 outb(devpriv->ai_act_chanlist[0] |
1036 (devpriv->ai_act_chanlist[seglen - 1] << 4),
1037 dev->iobase + PCL816_MUX);
1038}
1039
1040#ifdef unused
1041
1042
1043
1044
1045static int set_rtc_irq_bit(unsigned char bit)
1046{
1047 unsigned char val;
1048 unsigned long flags;
1049
1050 if (bit == 1) {
1051 RTC_timer_lock++;
1052 if (RTC_timer_lock > 1)
1053 return 0;
1054 } else {
1055 RTC_timer_lock--;
1056 if (RTC_timer_lock < 0)
1057 RTC_timer_lock = 0;
1058 if (RTC_timer_lock > 0)
1059 return 0;
1060 }
1061
1062 save_flags(flags);
1063 cli();
1064 val = CMOS_READ(RTC_CONTROL);
1065 if (bit)
1066 val |= RTC_PIE;
1067 else
1068 val &= ~RTC_PIE;
1069
1070 CMOS_WRITE(val, RTC_CONTROL);
1071 CMOS_READ(RTC_INTR_FLAGS);
1072 restore_flags(flags);
1073 return 0;
1074}
1075#endif
1076
1077
1078
1079
1080
1081static void free_resources(struct comedi_device *dev)
1082{
1083
1084 if (dev->private) {
1085 pcl816_ai_cancel(dev, devpriv->sub_ai);
1086 pcl816_reset(dev);
1087 if (devpriv->dma)
1088 free_dma(devpriv->dma);
1089 if (devpriv->dmabuf[0])
1090 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1091 if (devpriv->dmabuf[1])
1092 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1093#ifdef unused
1094 if (devpriv->rtc_irq)
1095 free_irq(devpriv->rtc_irq, dev);
1096 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1097 if (devpriv->rtc_iobase)
1098 release_region(devpriv->rtc_iobase,
1099 devpriv->rtc_iosize);
1100 }
1101#endif
1102 }
1103
1104 if (dev->irq)
1105 free_irq(dev->irq, dev);
1106 if (dev->iobase)
1107 release_region(dev->iobase, this_board->io_range);
1108
1109}
1110
1111
1112
1113
1114
1115
1116
1117static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1118{
1119 int ret;
1120 unsigned long iobase;
1121 unsigned int irq, dma;
1122 unsigned long pages;
1123
1124 struct comedi_subdevice *s;
1125
1126
1127 iobase = it->options[0];
1128 printk("comedi%d: pcl816: board=%s, ioport=0x%03lx", dev->minor,
1129 this_board->name, iobase);
1130
1131 if (!request_region(iobase, this_board->io_range, "pcl816")) {
1132 printk("I/O port conflict\n");
1133 return -EIO;
1134 }
1135
1136 dev->iobase = iobase;
1137
1138 if (pcl816_check(iobase)) {
1139 printk(KERN_ERR ", I cann't detect board. FAIL!\n");
1140 return -EIO;
1141 }
1142
1143 ret = alloc_private(dev, sizeof(struct pcl816_private));
1144 if (ret < 0)
1145 return ret;
1146
1147
1148 dev->board_name = this_board->name;
1149
1150
1151 irq = 0;
1152 if (this_board->IRQbits != 0) {
1153 irq = it->options[1];
1154 if (irq) {
1155 if (((1 << irq) & this_board->IRQbits) == 0) {
1156 printk
1157 (", IRQ %u is out of allowed range, "
1158 "DISABLING IT", irq);
1159 irq = 0;
1160 } else {
1161 if (request_irq
1162 (irq, interrupt_pcl816, 0, "pcl816", dev)) {
1163 printk
1164 (", unable to allocate IRQ %u, "
1165 "DISABLING IT", irq);
1166 irq = 0;
1167 } else {
1168 printk(KERN_INFO ", irq=%u", irq);
1169 }
1170 }
1171 }
1172 }
1173
1174 dev->irq = irq;
1175 if (irq)
1176 devpriv->irq_free = 1;
1177 else
1178 devpriv->irq_free = 0;
1179
1180 devpriv->irq_blocked = 0;
1181 devpriv->int816_mode = 0;
1182
1183#ifdef unused
1184
1185 devpriv->dma_rtc = 0;
1186 if (it->options[2] > 0) {
1187 if (RTC_lock == 0) {
1188 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1189 "pcl816 (RTC)"))
1190 goto no_rtc;
1191 }
1192 devpriv->rtc_iobase = RTC_PORT(0);
1193 devpriv->rtc_iosize = RTC_IO_EXTENT;
1194 RTC_lock++;
1195#ifdef UNTESTED_CODE
1196 if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
1197 "pcl816 DMA (RTC)", dev)) {
1198 devpriv->dma_rtc = 1;
1199 devpriv->rtc_irq = RTC_IRQ;
1200 printk(", dma_irq=%u", devpriv->rtc_irq);
1201 } else {
1202 RTC_lock--;
1203 if (RTC_lock == 0) {
1204 if (devpriv->rtc_iobase)
1205 release_region(devpriv->rtc_iobase,
1206 devpriv->rtc_iosize);
1207 }
1208 devpriv->rtc_iobase = 0;
1209 devpriv->rtc_iosize = 0;
1210 }
1211#else
1212 printk("pcl816: RTC code missing");
1213#endif
1214
1215 }
1216
1217no_rtc:
1218#endif
1219
1220 dma = 0;
1221 devpriv->dma = dma;
1222 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1223 goto no_dma;
1224
1225 if (this_board->DMAbits != 0) {
1226 dma = it->options[2];
1227 if (dma < 1)
1228 goto no_dma;
1229
1230 if (((1 << dma) & this_board->DMAbits) == 0) {
1231 printk(", DMA is out of allowed range, FAIL!\n");
1232 return -EINVAL;
1233 }
1234 ret = request_dma(dma, "pcl816");
1235 if (ret) {
1236 printk(KERN_ERR
1237 ", unable to allocate DMA %u, FAIL!\n", dma);
1238 return -EBUSY;
1239 }
1240
1241 devpriv->dma = dma;
1242 printk(KERN_INFO ", dma=%u", dma);
1243 pages = 2;
1244 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1245
1246 if (!devpriv->dmabuf[0]) {
1247 printk(", unable to allocate DMA buffer, FAIL!\n");
1248
1249
1250
1251
1252 return -EBUSY;
1253 }
1254 devpriv->dmapages[0] = pages;
1255 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1256 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1257
1258
1259 if (devpriv->dma_rtc == 0) {
1260 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1261 if (!devpriv->dmabuf[1]) {
1262 printk(KERN_ERR
1263 ", unable to allocate DMA buffer, "
1264 "FAIL!\n");
1265 return -EBUSY;
1266 }
1267 devpriv->dmapages[1] = pages;
1268 devpriv->hwdmaptr[1] =
1269 virt_to_bus((void *)devpriv->dmabuf[1]);
1270 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1271 }
1272 }
1273
1274no_dma:
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284 ret = alloc_subdevices(dev, 1);
1285 if (ret < 0)
1286 return ret;
1287
1288 s = dev->subdevices + 0;
1289 if (this_board->n_aichan > 0) {
1290 s->type = COMEDI_SUBD_AI;
1291 devpriv->sub_ai = s;
1292 dev->read_subdev = s;
1293 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1294 s->n_chan = this_board->n_aichan;
1295 s->subdev_flags |= SDF_DIFF;
1296
1297 s->maxdata = this_board->ai_maxdata;
1298 s->len_chanlist = this_board->ai_chanlist;
1299 s->range_table = this_board->ai_range_type;
1300 s->cancel = pcl816_ai_cancel;
1301 s->do_cmdtest = pcl816_ai_cmdtest;
1302 s->do_cmd = pcl816_ai_cmd;
1303 s->poll = pcl816_ai_poll;
1304 s->insn_read = pcl816_ai_insn_read;
1305 } else {
1306 s->type = COMEDI_SUBD_UNUSED;
1307 }
1308
1309#if 0
1310case COMEDI_SUBD_AO:
1311 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1312 s->n_chan = this_board->n_aochan;
1313 s->maxdata = this_board->ao_maxdata;
1314 s->len_chanlist = this_board->ao_chanlist;
1315 s->range_table = this_board->ao_range_type;
1316 break;
1317
1318case COMEDI_SUBD_DI:
1319 s->subdev_flags = SDF_READABLE;
1320 s->n_chan = this_board->n_dichan;
1321 s->maxdata = 1;
1322 s->len_chanlist = this_board->n_dichan;
1323 s->range_table = &range_digital;
1324 break;
1325
1326case COMEDI_SUBD_DO:
1327 s->subdev_flags = SDF_WRITABLE;
1328 s->n_chan = this_board->n_dochan;
1329 s->maxdata = 1;
1330 s->len_chanlist = this_board->n_dochan;
1331 s->range_table = &range_digital;
1332 break;
1333#endif
1334
1335 pcl816_reset(dev);
1336
1337 printk("\n");
1338
1339 return 0;
1340}
1341
1342
1343
1344
1345
1346static int pcl816_detach(struct comedi_device *dev)
1347{
1348 DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
1349 free_resources(dev);
1350#ifdef unused
1351 if (devpriv->dma_rtc)
1352 RTC_lock--;
1353#endif
1354 return 0;
1355}
1356
1357MODULE_AUTHOR("Comedi http://www.comedi.org");
1358MODULE_DESCRIPTION("Comedi low-level driver");
1359MODULE_LICENSE("GPL");
1360