2 comedi/drivers/pcl818.c
4 Author: Michal Dobes <dobes@tesnet.cz>
6 hardware driver for Advantech cards:
7 card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8 driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718
12 Description: Advantech PCL-818 cards, PCL-718
13 Author: Michal Dobes <dobes@tesnet.cz>
14 Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15 PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
19 All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20 Differences are only at maximal sample speed, range list and FIFO
22 The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23 only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24 PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25 but this code is untested.
26 A word or two about DMA. Driver support DMA operations at two ways:
27 1) DMA uses two buffers and after one is filled then is generated
28 INT and DMA restart with second buffer. With this mode I'm unable run
29 more that 80Ksamples/secs without data dropouts on K6/233.
30 2) DMA uses one buffer and run in autoinit mode and the data are
31 from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32 This mode is used if the interrupt 8 is available for allocation.
33 If not, then first DMA mode is used. With this I can run at
34 full speed one card (100ksamples/secs) or two cards with
35 60ksamples/secs each (more is problem on account of ISA limitations).
36 To use this mode you must have compiled kernel with disabled
37 "Enhanced Real Time Clock Support".
38 Maybe you can have problems if you use xntpd or similar.
39 If you've data dropouts with DMA mode 2 then:
41 b) switch text mode console to fb.
45 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
46 [2] - DMA (0=disable, 1, 3)
47 [3] - 0, 10=10MHz clock for 8254
48 1= 1MHz clock for 8254
49 [4] - 0, 5=A/D input -5V.. +5V
50 1, 10=A/D input -10V..+10V
51 [5] - 0, 5=D/A output 0-5V (internal reference -5V)
52 1, 10=D/A output 0-10V (internal reference -10V)
53 2 =D/A output unknown (external reference)
55 Options for PCL-818, PCL-818H:
57 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
58 [2] - DMA (0=disable, 1, 3)
59 [3] - 0, 10=10MHz clock for 8254
60 1= 1MHz clock for 8254
61 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
62 1, 10=D/A output 0-10V (internal reference -10V)
63 2 =D/A output unknown (external reference)
65 Options for PCL-818HD, PCL-818HG:
67 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
68 [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA,
69 1=use DMA ch 1, 3=use DMA ch 3)
70 [3] - 0, 10=10MHz clock for 8254
71 1= 1MHz clock for 8254
72 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
73 1, 10=D/A output 0-10V (internal reference -10V)
74 2 =D/A output unknown (external reference)
78 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
79 [2] - DMA (0=disable, 1, 3)
80 [3] - 0, 10=10MHz clock for 8254
81 1= 1MHz clock for 8254
82 [4] - 0=A/D Range is +/-10V
87 5= user defined bipolar
92 10= user defined unipolar
93 [5] - 0, 5=D/A outputs 0-5V (internal reference -5V)
94 1, 10=D/A outputs 0-10V (internal reference -10V)
95 2=D/A outputs unknown (external reference)
96 [6] - 0, 60=max 60kHz A/D sampling
97 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
101 #include <linux/module.h>
102 #include <linux/gfp.h>
103 #include <linux/delay.h>
104 #include <linux/io.h>
105 #include <linux/interrupt.h>
108 #include "../comedidev.h"
110 #include "comedi_fc.h"
113 /* #define PCL818_MODE13_AO 1 */
115 /* boards constants */
117 #define boardPCL818L 0
118 #define boardPCL818H 1
119 #define boardPCL818HD 2
120 #define boardPCL818HG 3
121 #define boardPCL818 4
122 #define boardPCL718 5
124 /* W: clear INT request */
125 #define PCL818_CLRINT 8
126 /* R: return status byte */
127 #define PCL818_STATUS 8
128 /* R: A/D high byte W: A/D range control */
129 #define PCL818_RANGE 1
130 /* R: next mux scan channel W: mux scan channel & range control pointer */
132 /* R/W: operation control register */
133 #define PCL818_CONTROL 9
134 /* W: counter enable */
135 #define PCL818_CNTENABLE 10
137 /* R: low byte of A/D W: soft A/D trigger */
138 #define PCL818_AD_LO 0
139 /* R: high byte of A/D W: A/D range control */
140 #define PCL818_AD_HI 1
141 /* W: D/A low&high byte */
142 #define PCL818_DA_LO 4
143 #define PCL818_DA_HI 5
144 /* R: low&high byte of DI */
145 #define PCL818_DI_LO 3
146 #define PCL818_DI_HI 11
147 /* W: low&high byte of DO */
148 #define PCL818_DO_LO 3
149 #define PCL818_DO_HI 11
150 /* W: PCL718 second D/A */
151 #define PCL718_DA2_LO 6
152 #define PCL718_DA2_HI 7
154 #define PCL818_CTR0 12
155 #define PCL818_CTR1 13
156 #define PCL818_CTR2 14
157 /* W: counter control */
158 #define PCL818_CTRCTL 15
160 /* W: fifo enable/disable */
161 #define PCL818_FI_ENABLE 6
162 /* W: fifo interrupt clear */
163 #define PCL818_FI_INTCLR 20
164 /* W: fifo interrupt clear */
165 #define PCL818_FI_FLUSH 25
167 #define PCL818_FI_STATUS 25
168 /* R: one record from FIFO */
169 #define PCL818_FI_DATALO 23
170 #define PCL818_FI_DATAHI 23
172 /* type of interrupt handler */
173 #define INT_TYPE_AI1_INT 1
174 #define INT_TYPE_AI1_DMA 2
175 #define INT_TYPE_AI1_FIFO 3
176 #define INT_TYPE_AI3_INT 4
177 #define INT_TYPE_AI3_DMA 5
178 #define INT_TYPE_AI3_FIFO 6
179 #ifdef PCL818_MODE13_AO
180 #define INT_TYPE_AO1_INT 7
181 #define INT_TYPE_AO3_INT 8
184 #define MAGIC_DMA_WORD 0x5a5a
186 static const struct comedi_lrange range_pcl818h_ai = {
200 static const struct comedi_lrange range_pcl818hg_ai = {
217 static const struct comedi_lrange range_pcl818l_l_ai = {
226 static const struct comedi_lrange range_pcl818l_h_ai = {
235 static const struct comedi_lrange range718_bipolar1 = {
241 static const struct comedi_lrange range718_bipolar0_5 = {
247 static const struct comedi_lrange range718_unipolar2 = {
253 static const struct comedi_lrange range718_unipolar1 = {
259 struct pcl818_board {
268 const struct comedi_lrange *ai_range_type;
269 const struct comedi_lrange *ao_range_type;
270 unsigned int IRQbits;
271 unsigned int DMAbits;
274 unsigned int has_fifo:1;
278 static const struct pcl818_board boardtypes[] = {
288 .ai_range_type = &range_pcl818l_l_ai,
289 .ao_range_type = &range_unipolar5,
304 .ai_range_type = &range_pcl818h_ai,
305 .ao_range_type = &range_unipolar5,
320 .ai_range_type = &range_pcl818h_ai,
321 .ao_range_type = &range_unipolar5,
337 .ai_range_type = &range_pcl818hg_ai,
338 .ao_range_type = &range_unipolar5,
354 .ai_range_type = &range_pcl818h_ai,
355 .ao_range_type = &range_unipolar5,
370 .ai_range_type = &range_unipolar5,
371 .ao_range_type = &range_unipolar5,
384 .ai_range_type = &range_pcl818h_ai,
385 .ao_range_type = &range_unipolar5,
394 struct pcl818_private {
396 unsigned int dma; /* used DMA, 0=don't use DMA */
397 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
398 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
399 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
400 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
401 int next_dma_buf; /* which DMA buffer will be used next round */
402 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
403 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
404 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
405 unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
406 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
407 int irq_blocked; /* 1=IRQ now uses any subdev */
408 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
409 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
410 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
411 int ai_act_scan; /* how many scans we finished */
412 int ai_act_chan; /* actual position in actual scan */
413 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
414 unsigned int act_chanlist_len; /* how long is actual MUX list */
415 unsigned int act_chanlist_pos; /* actual position in MUX list */
416 unsigned int ai_scans; /* len of scanlist */
417 unsigned int ai_n_chan; /* how many channels is measured */
418 unsigned int *ai_chanlist; /* actaul chanlist */
419 unsigned int ai_flags; /* flaglist */
420 unsigned int ai_data_len; /* len of data buffer */
421 unsigned int ai_timer1; /* timers */
422 unsigned int ai_timer2;
423 unsigned char usefifo; /* 1=use fifo */
424 unsigned int ao_readback[2];
427 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
428 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
432 ==============================================================================
434 static void setup_channel_list(struct comedi_device *dev,
435 struct comedi_subdevice *s,
436 unsigned int *chanlist, unsigned int n_chan,
437 unsigned int seglen);
438 static int check_channel_list(struct comedi_device *dev,
439 struct comedi_subdevice *s,
440 unsigned int *chanlist, unsigned int n_chan);
442 static int pcl818_ai_cancel(struct comedi_device *dev,
443 struct comedi_subdevice *s);
444 static void start_pacer(struct comedi_device *dev, int mode,
445 unsigned int divisor1, unsigned int divisor2);
447 static int pcl818_ai_eoc(struct comedi_device *dev,
448 struct comedi_subdevice *s,
449 struct comedi_insn *insn,
450 unsigned long context)
454 status = inb(dev->iobase + PCL818_STATUS);
460 static int pcl818_ai_insn_read(struct comedi_device *dev,
461 struct comedi_subdevice *s,
462 struct comedi_insn *insn, unsigned int *data)
467 /* software trigger, DMA and INT off */
468 outb(0, dev->iobase + PCL818_CONTROL);
471 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
474 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
476 for (n = 0; n < insn->n; n++) {
478 /* clear INT (conversion end) flag */
479 outb(0, dev->iobase + PCL818_CLRINT);
481 /* start conversion */
482 outb(0, dev->iobase + PCL818_AD_LO);
484 ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0);
486 /* clear INT (conversion end) flag */
487 outb(0, dev->iobase + PCL818_CLRINT);
491 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
492 (inb(dev->iobase + PCL818_AD_LO) >> 4));
499 ==============================================================================
500 ANALOG OUTPUT MODE0, 818 cards
501 only one sample per call is supported
503 static int pcl818_ao_insn_read(struct comedi_device *dev,
504 struct comedi_subdevice *s,
505 struct comedi_insn *insn, unsigned int *data)
507 struct pcl818_private *devpriv = dev->private;
509 int chan = CR_CHAN(insn->chanspec);
511 for (n = 0; n < insn->n; n++)
512 data[n] = devpriv->ao_readback[chan];
517 static int pcl818_ao_insn_write(struct comedi_device *dev,
518 struct comedi_subdevice *s,
519 struct comedi_insn *insn, unsigned int *data)
521 struct pcl818_private *devpriv = dev->private;
523 int chan = CR_CHAN(insn->chanspec);
525 for (n = 0; n < insn->n; n++) {
526 devpriv->ao_readback[chan] = data[n];
527 outb((data[n] & 0x000f) << 4, dev->iobase +
528 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
529 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
530 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
537 ==============================================================================
538 DIGITAL INPUT MODE0, 818 cards
540 only one sample per call is supported
542 static int pcl818_di_insn_bits(struct comedi_device *dev,
543 struct comedi_subdevice *s,
544 struct comedi_insn *insn, unsigned int *data)
546 data[1] = inb(dev->iobase + PCL818_DI_LO) |
547 (inb(dev->iobase + PCL818_DI_HI) << 8);
552 static int pcl818_do_insn_bits(struct comedi_device *dev,
553 struct comedi_subdevice *s,
554 struct comedi_insn *insn,
557 if (comedi_dio_update_state(s, data)) {
558 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
559 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
568 ==============================================================================
569 analog input interrupt mode 1 & 3, 818 cards
570 one sample per interrupt version
572 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
574 struct comedi_device *dev = d;
575 struct pcl818_private *devpriv = dev->private;
576 struct comedi_subdevice *s = dev->read_subdev;
578 int timeout = 50; /* wait max 50us */
581 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
585 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
586 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
587 pcl818_ai_cancel(dev, s);
588 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
589 comedi_event(dev, s);
593 low = inb(dev->iobase + PCL818_AD_LO);
594 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
595 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
597 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
598 dev_dbg(dev->class_dev,
599 "A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
601 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
602 pcl818_ai_cancel(dev, s);
603 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
604 comedi_event(dev, s);
607 devpriv->act_chanlist_pos++;
608 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
609 devpriv->act_chanlist_pos = 0;
611 s->async->cur_chan++;
612 if (s->async->cur_chan >= devpriv->ai_n_chan) {
613 s->async->cur_chan = 0;
614 devpriv->ai_act_scan--;
617 if (!devpriv->neverending_ai) {
618 if (devpriv->ai_act_scan == 0) { /* all data sampled */
619 pcl818_ai_cancel(dev, s);
620 s->async->events |= COMEDI_CB_EOA;
623 comedi_event(dev, s);
628 ==============================================================================
629 analog input dma mode 1 & 3, 818 cards
631 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
633 struct comedi_device *dev = d;
634 struct pcl818_private *devpriv = dev->private;
635 struct comedi_subdevice *s = dev->read_subdev;
640 disable_dma(devpriv->dma);
641 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
642 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
643 set_dma_mode(devpriv->dma, DMA_MODE_READ);
644 flags = claim_dma_lock();
645 set_dma_addr(devpriv->dma,
646 devpriv->hwdmaptr[devpriv->next_dma_buf]);
647 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
648 set_dma_count(devpriv->dma,
649 devpriv->hwdmasize[devpriv->
652 set_dma_count(devpriv->dma, devpriv->last_dma_run);
654 release_dma_lock(flags);
655 enable_dma(devpriv->dma);
658 devpriv->dma_runs_to_end--;
659 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
660 ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
662 len = devpriv->hwdmasize[0] >> 1;
665 for (i = 0; i < len; i++) {
666 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
667 dev_dbg(dev->class_dev,
668 "A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
670 devpriv->act_chanlist[devpriv->act_chanlist_pos],
671 devpriv->act_chanlist_pos);
672 pcl818_ai_cancel(dev, s);
673 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
674 comedi_event(dev, s);
678 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
680 devpriv->act_chanlist_pos++;
681 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
682 devpriv->act_chanlist_pos = 0;
684 s->async->cur_chan++;
685 if (s->async->cur_chan >= devpriv->ai_n_chan) {
686 s->async->cur_chan = 0;
687 devpriv->ai_act_scan--;
690 if (!devpriv->neverending_ai)
691 if (devpriv->ai_act_scan == 0) { /* all data sampled */
692 pcl818_ai_cancel(dev, s);
693 s->async->events |= COMEDI_CB_EOA;
694 comedi_event(dev, s);
700 comedi_event(dev, s);
705 ==============================================================================
706 analog input interrupt mode 1 & 3, 818HD/HG cards
708 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
710 struct comedi_device *dev = d;
711 struct pcl818_private *devpriv = dev->private;
712 struct comedi_subdevice *s = dev->read_subdev;
716 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
718 lo = inb(dev->iobase + PCL818_FI_STATUS);
721 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
722 pcl818_ai_cancel(dev, s);
723 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
724 comedi_event(dev, s);
729 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
730 pcl818_ai_cancel(dev, s);
731 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
732 comedi_event(dev, s);
741 for (i = 0; i < len; i++) {
742 lo = inb(dev->iobase + PCL818_FI_DATALO);
743 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
744 dev_dbg(dev->class_dev,
745 "A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
747 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
748 pcl818_ai_cancel(dev, s);
749 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
750 comedi_event(dev, s);
754 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
756 devpriv->act_chanlist_pos++;
757 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
758 devpriv->act_chanlist_pos = 0;
760 s->async->cur_chan++;
761 if (s->async->cur_chan >= devpriv->ai_n_chan) {
762 s->async->cur_chan = 0;
763 devpriv->ai_act_scan--;
766 if (!devpriv->neverending_ai)
767 if (devpriv->ai_act_scan == 0) { /* all data sampled */
768 pcl818_ai_cancel(dev, s);
769 s->async->events |= COMEDI_CB_EOA;
770 comedi_event(dev, s);
776 comedi_event(dev, s);
781 ==============================================================================
784 static irqreturn_t interrupt_pcl818(int irq, void *d)
786 struct comedi_device *dev = d;
787 struct pcl818_private *devpriv = dev->private;
789 if (!dev->attached) {
790 comedi_error(dev, "premature interrupt");
794 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
795 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
796 devpriv->ai_act_scan > 0)) &&
797 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
798 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
799 /* The cleanup from ai_cancel() has been delayed
800 until now because the card doesn't seem to like
801 being reprogrammed while a DMA transfer is in
804 devpriv->ai_act_scan = 0;
805 devpriv->neverending_ai = 0;
806 pcl818_ai_cancel(dev, dev->read_subdev);
809 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
814 switch (devpriv->ai_mode) {
815 case INT_TYPE_AI1_DMA:
816 case INT_TYPE_AI3_DMA:
817 return interrupt_pcl818_ai_mode13_dma(irq, d);
818 case INT_TYPE_AI1_INT:
819 case INT_TYPE_AI3_INT:
820 return interrupt_pcl818_ai_mode13_int(irq, d);
821 case INT_TYPE_AI1_FIFO:
822 case INT_TYPE_AI3_FIFO:
823 return interrupt_pcl818_ai_mode13_fifo(irq, d);
824 #ifdef PCL818_MODE13_AO
825 case INT_TYPE_AO1_INT:
826 case INT_TYPE_AO3_INT:
827 return interrupt_pcl818_ao_mode13_int(irq, d);
833 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
835 if (!devpriv->irq_blocked || !devpriv->ai_mode) {
836 comedi_error(dev, "bad IRQ!");
840 comedi_error(dev, "IRQ from unknown source!");
845 ==============================================================================
846 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
848 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
849 struct comedi_subdevice *s)
851 struct pcl818_private *devpriv = dev->private;
855 disable_dma(devpriv->dma); /* disable dma */
856 bytes = devpriv->hwdmasize[0];
857 if (!devpriv->neverending_ai) {
858 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
859 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
860 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
861 devpriv->dma_runs_to_end--;
862 if (devpriv->dma_runs_to_end >= 0)
863 bytes = devpriv->hwdmasize[0];
866 devpriv->next_dma_buf = 0;
867 set_dma_mode(devpriv->dma, DMA_MODE_READ);
868 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, bytes);
872 release_dma_lock(flags);
873 enable_dma(devpriv->dma);
876 devpriv->ai_mode = INT_TYPE_AI1_DMA;
877 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
879 devpriv->ai_mode = INT_TYPE_AI3_DMA;
880 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
885 ==============================================================================
886 ANALOG INPUT MODE 1 or 3, 818 cards
888 static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
889 struct comedi_subdevice *s)
891 struct pcl818_private *devpriv = dev->private;
892 struct comedi_cmd *cmd = &s->async->cmd;
893 int divisor1 = 0, divisor2 = 0;
896 if (devpriv->irq_blocked)
899 start_pacer(dev, -1, 0, 0); /* stop pacer */
901 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
905 setup_channel_list(dev, s, devpriv->ai_chanlist,
906 devpriv->ai_n_chan, seglen);
910 devpriv->ai_act_scan = devpriv->ai_scans;
911 devpriv->ai_act_chan = 0;
912 devpriv->irq_blocked = 1;
913 devpriv->irq_was_now_closed = 0;
914 devpriv->neverending_ai = 0;
915 devpriv->act_chanlist_pos = 0;
916 devpriv->dma_runs_to_end = 0;
918 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
919 devpriv->neverending_ai = 1; /* well, user want neverending */
922 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
923 &divisor1, &divisor2,
926 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
936 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
938 switch (devpriv->dma) {
941 pcl818_ai_mode13dma_int(mode, dev, s);
944 if (!devpriv->usefifo) {
947 devpriv->ai_mode = INT_TYPE_AI1_INT;
949 outb(0x83 | (dev->irq << 4),
950 dev->iobase + PCL818_CONTROL);
952 devpriv->ai_mode = INT_TYPE_AI3_INT;
954 outb(0x82 | (dev->irq << 4),
955 dev->iobase + PCL818_CONTROL);
960 outb(1, dev->iobase + PCL818_FI_ENABLE);
962 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
964 outb(0x03, dev->iobase + PCL818_CONTROL);
966 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
967 outb(0x02, dev->iobase + PCL818_CONTROL);
972 start_pacer(dev, mode, divisor1, divisor2);
978 ==============================================================================
979 Start/stop pacer onboard pacer
981 static void start_pacer(struct comedi_device *dev, int mode,
982 unsigned int divisor1, unsigned int divisor2)
984 outb(0xb4, dev->iobase + PCL818_CTRCTL);
985 outb(0x74, dev->iobase + PCL818_CTRCTL);
989 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
990 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
991 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
992 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
997 ==============================================================================
998 Check if channel list from user is builded correctly
999 If it's ok, then program scan/gain logic
1001 static int check_channel_list(struct comedi_device *dev,
1002 struct comedi_subdevice *s,
1003 unsigned int *chanlist, unsigned int n_chan)
1005 unsigned int chansegment[16];
1006 unsigned int i, nowmustbechan, seglen, segpos;
1008 /* correct channel and range number check itself comedi/range.c */
1010 comedi_error(dev, "range/channel list is empty!");
1015 /* first channel is every time ok */
1016 chansegment[0] = chanlist[0];
1017 /* build part of chanlist */
1018 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1019 /* we detect loop, this must by finish */
1021 if (chanlist[0] == chanlist[i])
1024 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1025 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
1026 dev_dbg(dev->class_dev,
1027 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1028 i, CR_CHAN(chanlist[i]), nowmustbechan,
1029 CR_CHAN(chanlist[0]));
1032 /* well, this is next correct channel in list */
1033 chansegment[i] = chanlist[i];
1036 /* check whole chanlist */
1037 for (i = 0, segpos = 0; i < n_chan; i++) {
1038 if (chanlist[i] != chansegment[i % seglen]) {
1039 dev_dbg(dev->class_dev,
1040 "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1041 i, CR_CHAN(chansegment[i]),
1042 CR_RANGE(chansegment[i]),
1043 CR_AREF(chansegment[i]),
1044 CR_CHAN(chanlist[i % seglen]),
1045 CR_RANGE(chanlist[i % seglen]),
1046 CR_AREF(chansegment[i % seglen]));
1047 return 0; /* chan/gain list is strange */
1056 static void setup_channel_list(struct comedi_device *dev,
1057 struct comedi_subdevice *s,
1058 unsigned int *chanlist, unsigned int n_chan,
1059 unsigned int seglen)
1061 struct pcl818_private *devpriv = dev->private;
1064 devpriv->act_chanlist_len = seglen;
1065 devpriv->act_chanlist_pos = 0;
1067 for (i = 0; i < seglen; i++) { /* store range list to card */
1068 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1069 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1070 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1075 /* select channel interval to scan */
1076 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1078 dev->iobase + PCL818_MUX);
1082 ==============================================================================
1083 Check if board is switched to SE (1) or DIFF(0) mode
1085 static int check_single_ended(unsigned int port)
1087 if (inb(port + PCL818_STATUS) & 0x20)
1093 ==============================================================================
1095 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1096 struct comedi_cmd *cmd)
1098 const struct pcl818_board *board = comedi_board(dev);
1099 struct pcl818_private *devpriv = dev->private;
1101 int tmp, divisor1 = 0, divisor2 = 0;
1103 /* Step 1 : check if triggers are trivially valid */
1105 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
1106 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1107 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1108 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1109 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1114 /* Step 2a : make sure trigger sources are unique */
1116 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1117 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1119 /* Step 2b : and mutually compatible */
1124 /* Step 3: check if arguments are trivially valid */
1126 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1127 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1129 if (cmd->convert_src == TRIG_TIMER)
1130 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1133 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1135 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1137 if (cmd->stop_src == TRIG_COUNT)
1138 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1139 else /* TRIG_NONE */
1140 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1145 /* step 4: fix up any arguments */
1147 if (cmd->convert_src == TRIG_TIMER) {
1148 tmp = cmd->convert_arg;
1149 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
1150 &divisor1, &divisor2,
1151 &cmd->convert_arg, cmd->flags);
1152 if (cmd->convert_arg < board->ns_min)
1153 cmd->convert_arg = board->ns_min;
1154 if (tmp != cmd->convert_arg)
1161 /* step 5: complain about special chanlist considerations */
1163 if (cmd->chanlist) {
1164 if (!check_channel_list(dev, s, cmd->chanlist,
1166 return 5; /* incorrect channels list */
1173 ==============================================================================
1175 static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1177 struct pcl818_private *devpriv = dev->private;
1178 struct comedi_cmd *cmd = &s->async->cmd;
1181 devpriv->ai_n_chan = cmd->chanlist_len;
1182 devpriv->ai_chanlist = cmd->chanlist;
1183 devpriv->ai_flags = cmd->flags;
1184 devpriv->ai_data_len = s->async->prealloc_bufsz;
1185 devpriv->ai_timer1 = 0;
1186 devpriv->ai_timer2 = 0;
1188 if (cmd->stop_src == TRIG_COUNT)
1189 devpriv->ai_scans = cmd->stop_arg;
1191 devpriv->ai_scans = 0;
1193 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1194 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
1195 devpriv->ai_timer1 = cmd->convert_arg;
1196 retval = pcl818_ai_cmd_mode(1, dev, s);
1199 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1200 return pcl818_ai_cmd_mode(3, dev, s);
1208 ==============================================================================
1209 cancel any mode 1-4 AI
1211 static int pcl818_ai_cancel(struct comedi_device *dev,
1212 struct comedi_subdevice *s)
1214 struct pcl818_private *devpriv = dev->private;
1216 if (devpriv->irq_blocked > 0) {
1217 devpriv->irq_was_now_closed = 1;
1219 switch (devpriv->ai_mode) {
1220 case INT_TYPE_AI1_DMA:
1221 case INT_TYPE_AI3_DMA:
1222 if (devpriv->neverending_ai ||
1223 (!devpriv->neverending_ai &&
1224 devpriv->ai_act_scan > 0)) {
1225 /* wait for running dma transfer to end, do cleanup in interrupt */
1228 disable_dma(devpriv->dma);
1229 case INT_TYPE_AI1_INT:
1230 case INT_TYPE_AI3_INT:
1231 case INT_TYPE_AI1_FIFO:
1232 case INT_TYPE_AI3_FIFO:
1233 #ifdef PCL818_MODE13_AO
1234 case INT_TYPE_AO1_INT:
1235 case INT_TYPE_AO3_INT:
1237 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1239 start_pacer(dev, -1, 0, 0);
1240 outb(0, dev->iobase + PCL818_AD_LO);
1241 inb(dev->iobase + PCL818_AD_LO);
1242 inb(dev->iobase + PCL818_AD_HI);
1243 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1244 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1245 if (devpriv->usefifo) { /* FIFO shutdown */
1246 outb(0, dev->iobase + PCL818_FI_INTCLR);
1247 outb(0, dev->iobase + PCL818_FI_FLUSH);
1248 outb(0, dev->iobase + PCL818_FI_ENABLE);
1250 devpriv->irq_blocked = 0;
1251 devpriv->last_int_sub = s;
1252 devpriv->neverending_ai = 0;
1253 devpriv->ai_mode = 0;
1254 devpriv->irq_was_now_closed = 0;
1264 ==============================================================================
1267 static int pcl818_check(unsigned long iobase)
1269 outb(0x00, iobase + PCL818_MUX);
1271 if (inb(iobase + PCL818_MUX) != 0x00)
1272 return 1; /* there isn't card */
1273 outb(0x55, iobase + PCL818_MUX);
1275 if (inb(iobase + PCL818_MUX) != 0x55)
1276 return 1; /* there isn't card */
1277 outb(0x00, iobase + PCL818_MUX);
1279 outb(0x18, iobase + PCL818_CONTROL);
1281 if (inb(iobase + PCL818_CONTROL) != 0x18)
1282 return 1; /* there isn't card */
1283 return 0; /* ok, card exist */
1287 ==============================================================================
1288 reset whole PCL-818 cards
1290 static void pcl818_reset(struct comedi_device *dev)
1292 const struct pcl818_board *board = comedi_board(dev);
1293 struct pcl818_private *devpriv = dev->private;
1295 if (devpriv->usefifo) { /* FIFO shutdown */
1296 outb(0, dev->iobase + PCL818_FI_INTCLR);
1297 outb(0, dev->iobase + PCL818_FI_FLUSH);
1298 outb(0, dev->iobase + PCL818_FI_ENABLE);
1300 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
1301 outb(0, dev->iobase + PCL818_DA_HI);
1303 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
1304 outb(0, dev->iobase + PCL818_DO_LO);
1306 outb(0, dev->iobase + PCL818_CONTROL);
1307 outb(0, dev->iobase + PCL818_CNTENABLE);
1308 outb(0, dev->iobase + PCL818_MUX);
1309 outb(0, dev->iobase + PCL818_CLRINT);
1310 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1311 outb(0x70, dev->iobase + PCL818_CTRCTL);
1312 outb(0x30, dev->iobase + PCL818_CTRCTL);
1313 if (board->is_818) {
1314 outb(0, dev->iobase + PCL818_RANGE);
1316 outb(0, dev->iobase + PCL718_DA2_LO);
1317 outb(0, dev->iobase + PCL718_DA2_HI);
1321 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1323 const struct pcl818_board *board = comedi_board(dev);
1324 struct pcl818_private *devpriv;
1327 unsigned long pages;
1328 struct comedi_subdevice *s;
1330 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1334 /* should we use the FIFO? */
1335 if (board->has_fifo && it->options[2] == -1)
1336 devpriv->usefifo = 1;
1338 ret = comedi_request_region(dev, it->options[0],
1339 devpriv->usefifo ? 0x20 : 0x10);
1343 if (pcl818_check(dev->iobase)) {
1344 comedi_error(dev, "I can't detect board. FAIL!\n");
1348 if ((1 << it->options[1]) & board->IRQbits) {
1349 ret = request_irq(it->options[1], interrupt_pcl818, 0,
1350 dev->board_name, dev);
1352 dev->irq = it->options[1];
1355 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1356 devpriv->ai_mode = 0; /* mode of irq */
1362 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1363 if (board->DMAbits != 0) { /* board support DMA */
1364 dma = it->options[2];
1366 goto no_dma; /* DMA disabled */
1367 if (((1 << dma) & board->DMAbits) == 0) {
1368 dev_err(dev->class_dev,
1369 "DMA is out of allowed range, FAIL!\n");
1370 return -EINVAL; /* Bad DMA */
1372 ret = request_dma(dma, dev->board_name);
1374 return -EBUSY; /* DMA isn't free */
1376 pages = 2; /* we need 16KB */
1377 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1378 if (!devpriv->dmabuf[0])
1379 /* maybe experiment with try_to_free_pages() will help .... */
1380 return -EBUSY; /* no buffer :-( */
1381 devpriv->dmapages[0] = pages;
1382 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1383 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1384 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1385 if (!devpriv->dmabuf[1])
1387 devpriv->dmapages[1] = pages;
1388 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1389 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1394 ret = comedi_alloc_subdevices(dev, 4);
1398 s = &dev->subdevices[0];
1399 if (!board->n_aichan_se) {
1400 s->type = COMEDI_SUBD_UNUSED;
1402 s->type = COMEDI_SUBD_AI;
1403 s->subdev_flags = SDF_READABLE;
1404 if (check_single_ended(dev->iobase)) {
1405 s->n_chan = board->n_aichan_se;
1406 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1408 s->n_chan = board->n_aichan_diff;
1409 s->subdev_flags |= SDF_DIFF;
1411 s->maxdata = board->ai_maxdata;
1412 s->range_table = board->ai_range_type;
1413 s->insn_read = pcl818_ai_insn_read;
1415 dev->read_subdev = s;
1416 s->subdev_flags |= SDF_CMD_READ;
1417 s->len_chanlist = s->n_chan;
1418 s->do_cmdtest = ai_cmdtest;
1420 s->cancel = pcl818_ai_cancel;
1422 if (board->is_818) {
1423 if ((it->options[4] == 1) || (it->options[4] == 10))
1424 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
1426 switch (it->options[4]) {
1428 s->range_table = &range_bipolar10;
1431 s->range_table = &range_bipolar5;
1434 s->range_table = &range_bipolar2_5;
1437 s->range_table = &range718_bipolar1;
1440 s->range_table = &range718_bipolar0_5;
1443 s->range_table = &range_unipolar10;
1446 s->range_table = &range_unipolar5;
1449 s->range_table = &range718_unipolar2;
1452 s->range_table = &range718_unipolar1;
1455 s->range_table = &range_unknown;
1461 s = &dev->subdevices[1];
1462 if (!board->n_aochan) {
1463 s->type = COMEDI_SUBD_UNUSED;
1465 s->type = COMEDI_SUBD_AO;
1466 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1467 s->n_chan = board->n_aochan;
1468 s->maxdata = board->ao_maxdata;
1469 s->range_table = board->ao_range_type;
1470 s->insn_read = pcl818_ao_insn_read;
1471 s->insn_write = pcl818_ao_insn_write;
1472 if (board->is_818) {
1473 if ((it->options[4] == 1) || (it->options[4] == 10))
1474 s->range_table = &range_unipolar10;
1475 if (it->options[4] == 2)
1476 s->range_table = &range_unknown;
1478 if ((it->options[5] == 1) || (it->options[5] == 10))
1479 s->range_table = &range_unipolar10;
1480 if (it->options[5] == 2)
1481 s->range_table = &range_unknown;
1485 s = &dev->subdevices[2];
1486 if (!board->n_dichan) {
1487 s->type = COMEDI_SUBD_UNUSED;
1489 s->type = COMEDI_SUBD_DI;
1490 s->subdev_flags = SDF_READABLE;
1491 s->n_chan = board->n_dichan;
1493 s->range_table = &range_digital;
1494 s->insn_bits = pcl818_di_insn_bits;
1497 s = &dev->subdevices[3];
1498 if (!board->n_dochan) {
1499 s->type = COMEDI_SUBD_UNUSED;
1501 s->type = COMEDI_SUBD_DO;
1502 s->subdev_flags = SDF_WRITABLE;
1503 s->n_chan = board->n_dochan;
1505 s->range_table = &range_digital;
1506 s->insn_bits = pcl818_do_insn_bits;
1509 /* select 1/10MHz oscilator */
1510 if ((it->options[3] == 0) || (it->options[3] == 10))
1511 devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ;
1513 devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ;
1515 /* max sampling speed */
1516 devpriv->ns_min = board->ns_min;
1518 if (!board->is_818) {
1519 if ((it->options[6] == 1) || (it->options[6] == 100))
1520 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1528 static void pcl818_detach(struct comedi_device *dev)
1530 struct pcl818_private *devpriv = dev->private;
1533 pcl818_ai_cancel(dev, dev->read_subdev);
1536 free_dma(devpriv->dma);
1537 if (devpriv->dmabuf[0])
1538 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1539 if (devpriv->dmabuf[1])
1540 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1542 comedi_legacy_detach(dev);
1545 static struct comedi_driver pcl818_driver = {
1546 .driver_name = "pcl818",
1547 .module = THIS_MODULE,
1548 .attach = pcl818_attach,
1549 .detach = pcl818_detach,
1550 .board_name = &boardtypes[0].name,
1551 .num_names = ARRAY_SIZE(boardtypes),
1552 .offset = sizeof(struct pcl818_board),
1554 module_comedi_driver(pcl818_driver);
1556 MODULE_AUTHOR("Comedi http://www.comedi.org");
1557 MODULE_DESCRIPTION("Comedi low-level driver");
1558 MODULE_LICENSE("GPL");