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 "../comedidev.h"
103 #include <linux/ioport.h>
104 #include <linux/mc146818rtc.h>
105 #include <linux/gfp.h>
106 #include <linux/delay.h>
107 #include <linux/io.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
125 #define PCLx1x_RANGE 16
126 /* IO space len if we use FIFO */
127 #define PCLx1xFIFO_RANGE 32
129 /* W: clear INT request */
130 #define PCL818_CLRINT 8
131 /* R: return status byte */
132 #define PCL818_STATUS 8
133 /* R: A/D high byte W: A/D range control */
134 #define PCL818_RANGE 1
135 /* R: next mux scan channel W: mux scan channel & range control pointer */
137 /* R/W: operation control register */
138 #define PCL818_CONTROL 9
139 /* W: counter enable */
140 #define PCL818_CNTENABLE 10
142 /* R: low byte of A/D W: soft A/D trigger */
143 #define PCL818_AD_LO 0
144 /* R: high byte of A/D W: A/D range control */
145 #define PCL818_AD_HI 1
146 /* W: D/A low&high byte */
147 #define PCL818_DA_LO 4
148 #define PCL818_DA_HI 5
149 /* R: low&high byte of DI */
150 #define PCL818_DI_LO 3
151 #define PCL818_DI_HI 11
152 /* W: low&high byte of DO */
153 #define PCL818_DO_LO 3
154 #define PCL818_DO_HI 11
155 /* W: PCL718 second D/A */
156 #define PCL718_DA2_LO 6
157 #define PCL718_DA2_HI 7
159 #define PCL818_CTR0 12
160 #define PCL818_CTR1 13
161 #define PCL818_CTR2 14
162 /* W: counter control */
163 #define PCL818_CTRCTL 15
165 /* W: fifo enable/disable */
166 #define PCL818_FI_ENABLE 6
167 /* W: fifo interrupt clear */
168 #define PCL818_FI_INTCLR 20
169 /* W: fifo interrupt clear */
170 #define PCL818_FI_FLUSH 25
172 #define PCL818_FI_STATUS 25
173 /* R: one record from FIFO */
174 #define PCL818_FI_DATALO 23
175 #define PCL818_FI_DATAHI 23
177 /* type of interrupt handler */
178 #define INT_TYPE_AI1_INT 1
179 #define INT_TYPE_AI1_DMA 2
180 #define INT_TYPE_AI1_FIFO 3
181 #define INT_TYPE_AI3_INT 4
182 #define INT_TYPE_AI3_DMA 5
183 #define INT_TYPE_AI3_FIFO 6
184 #ifdef PCL818_MODE13_AO
185 #define INT_TYPE_AO1_INT 7
186 #define INT_TYPE_AO3_INT 8
191 #define INT_TYPE_AI1_DMA_RTC 9
192 #define INT_TYPE_AI3_DMA_RTC 10
195 #define RTC_IO_EXTENT 0x10
198 #define MAGIC_DMA_WORD 0x5a5a
200 static const struct comedi_lrange range_pcl818h_ai = { 9, {
213 static const struct comedi_lrange range_pcl818hg_ai = { 10, {
229 static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
237 static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
245 static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
246 static const struct comedi_lrange range718_bipolar0_5 = {
247 1, {BIP_RANGE(0.5),} };
248 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
249 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
252 static int RTC_lock; /* RTC lock */
253 static int RTC_timer_lock; /* RTC int lock */
256 struct pcl818_board {
258 const char *name; /* driver name */
259 int n_ranges; /* len of range list */
260 int n_aichan_se; /* num of A/D chans in single ended mode */
261 int n_aichan_diff; /* num of A/D chans in diferencial mode */
262 unsigned int ns_min; /* minimal allowed delay between samples (in ns) */
263 int n_aochan; /* num of D/A chans */
264 int n_dichan; /* num of DI chans */
265 int n_dochan; /* num of DO chans */
266 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
267 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
268 unsigned int io_range; /* len of IO space */
269 unsigned int IRQbits; /* allowed interrupts */
270 unsigned int DMAbits; /* allowed DMA chans */
271 int ai_maxdata; /* maxdata for A/D */
272 int ao_maxdata; /* maxdata for D/A */
273 unsigned char fifo; /* 1=board has FIFO */
277 struct pcl818_private {
279 unsigned int dma; /* used DMA, 0=don't use DMA */
280 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
281 unsigned int io_range;
283 unsigned long rtc_iobase; /* RTC port region */
284 unsigned int rtc_iosize;
285 unsigned int rtc_irq;
286 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
287 unsigned long rtc_freq; /* RTC int freq */
288 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
290 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
291 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
292 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
293 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
294 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
295 unsigned int last_top_dma; /* DMA pointer in last RTC int */
296 int next_dma_buf; /* which DMA buffer will be used next round */
297 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
298 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
299 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
300 unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
301 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
302 int irq_free; /* 1=have allocated IRQ */
303 int irq_blocked; /* 1=IRQ now uses any subdev */
304 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
305 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
306 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
307 int ai_act_scan; /* how many scans we finished */
308 int ai_act_chan; /* actual position in actual scan */
309 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
310 unsigned int act_chanlist_len; /* how long is actual MUX list */
311 unsigned int act_chanlist_pos; /* actual position in MUX list */
312 unsigned int ai_scans; /* len of scanlist */
313 unsigned int ai_n_chan; /* how many channels is measured */
314 unsigned int *ai_chanlist; /* actaul chanlist */
315 unsigned int ai_flags; /* flaglist */
316 unsigned int ai_data_len; /* len of data buffer */
317 short *ai_data; /* data buffer */
318 unsigned int ai_timer1; /* timers */
319 unsigned int ai_timer2;
320 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
321 unsigned char usefifo; /* 1=use fifo */
322 unsigned int ao_readback[2];
325 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
326 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
330 ==============================================================================
332 static void setup_channel_list(struct comedi_device *dev,
333 struct comedi_subdevice *s,
334 unsigned int *chanlist, unsigned int n_chan,
335 unsigned int seglen);
336 static int check_channel_list(struct comedi_device *dev,
337 struct comedi_subdevice *s,
338 unsigned int *chanlist, unsigned int n_chan);
340 static int pcl818_ai_cancel(struct comedi_device *dev,
341 struct comedi_subdevice *s);
342 static void start_pacer(struct comedi_device *dev, int mode,
343 unsigned int divisor1, unsigned int divisor2);
346 static int set_rtc_irq_bit(unsigned char bit);
347 static void rtc_dropped_irq(unsigned long data);
348 static int rtc_setfreq_irq(int freq);
352 ==============================================================================
353 ANALOG INPUT MODE0, 818 cards, slow version
355 static int pcl818_ai_insn_read(struct comedi_device *dev,
356 struct comedi_subdevice *s,
357 struct comedi_insn *insn, unsigned int *data)
362 /* software trigger, DMA and INT off */
363 outb(0, dev->iobase + PCL818_CONTROL);
366 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
369 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
371 for (n = 0; n < insn->n; n++) {
373 /* clear INT (conversion end) flag */
374 outb(0, dev->iobase + PCL818_CLRINT);
376 /* start conversion */
377 outb(0, dev->iobase + PCL818_AD_LO);
381 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
385 comedi_error(dev, "A/D insn timeout");
386 /* clear INT (conversion end) flag */
387 outb(0, dev->iobase + PCL818_CLRINT);
391 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
392 (inb(dev->iobase + PCL818_AD_LO) >> 4));
399 ==============================================================================
400 ANALOG OUTPUT MODE0, 818 cards
401 only one sample per call is supported
403 static int pcl818_ao_insn_read(struct comedi_device *dev,
404 struct comedi_subdevice *s,
405 struct comedi_insn *insn, unsigned int *data)
407 struct pcl818_private *devpriv = dev->private;
409 int chan = CR_CHAN(insn->chanspec);
411 for (n = 0; n < insn->n; n++)
412 data[n] = devpriv->ao_readback[chan];
417 static int pcl818_ao_insn_write(struct comedi_device *dev,
418 struct comedi_subdevice *s,
419 struct comedi_insn *insn, unsigned int *data)
421 struct pcl818_private *devpriv = dev->private;
423 int chan = CR_CHAN(insn->chanspec);
425 for (n = 0; n < insn->n; n++) {
426 devpriv->ao_readback[chan] = data[n];
427 outb((data[n] & 0x000f) << 4, dev->iobase +
428 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
429 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
430 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
437 ==============================================================================
438 DIGITAL INPUT MODE0, 818 cards
440 only one sample per call is supported
442 static int pcl818_di_insn_bits(struct comedi_device *dev,
443 struct comedi_subdevice *s,
444 struct comedi_insn *insn, unsigned int *data)
446 data[1] = inb(dev->iobase + PCL818_DI_LO) |
447 (inb(dev->iobase + PCL818_DI_HI) << 8);
453 ==============================================================================
454 DIGITAL OUTPUT MODE0, 818 cards
456 only one sample per call is supported
458 static int pcl818_do_insn_bits(struct comedi_device *dev,
459 struct comedi_subdevice *s,
460 struct comedi_insn *insn, unsigned int *data)
462 s->state &= ~data[0];
463 s->state |= (data[0] & data[1]);
465 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
466 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
474 ==============================================================================
475 analog input interrupt mode 1 & 3, 818 cards
476 one sample per interrupt version
478 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
480 struct comedi_device *dev = d;
481 struct pcl818_private *devpriv = dev->private;
482 struct comedi_subdevice *s = &dev->subdevices[0];
484 int timeout = 50; /* wait max 50us */
487 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
491 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
492 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
493 pcl818_ai_cancel(dev, s);
494 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
495 comedi_event(dev, s);
499 low = inb(dev->iobase + PCL818_AD_LO);
500 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
501 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
503 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
505 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
507 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
508 pcl818_ai_cancel(dev, s);
509 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
510 comedi_event(dev, s);
513 devpriv->act_chanlist_pos++;
514 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
515 devpriv->act_chanlist_pos = 0;
517 s->async->cur_chan++;
518 if (s->async->cur_chan >= devpriv->ai_n_chan) {
520 s->async->cur_chan = 0;
521 devpriv->ai_act_scan--;
524 if (!devpriv->neverending_ai) {
525 if (devpriv->ai_act_scan == 0) { /* all data sampled */
526 pcl818_ai_cancel(dev, s);
527 s->async->events |= COMEDI_CB_EOA;
530 comedi_event(dev, s);
535 ==============================================================================
536 analog input dma mode 1 & 3, 818 cards
538 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
540 struct comedi_device *dev = d;
541 struct pcl818_private *devpriv = dev->private;
542 struct comedi_subdevice *s = &dev->subdevices[0];
547 disable_dma(devpriv->dma);
548 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
549 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
550 set_dma_mode(devpriv->dma, DMA_MODE_READ);
551 flags = claim_dma_lock();
552 set_dma_addr(devpriv->dma,
553 devpriv->hwdmaptr[devpriv->next_dma_buf]);
554 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
555 set_dma_count(devpriv->dma,
556 devpriv->hwdmasize[devpriv->
559 set_dma_count(devpriv->dma, devpriv->last_dma_run);
561 release_dma_lock(flags);
562 enable_dma(devpriv->dma);
564 printk("comedi: A/D mode1/3 IRQ \n");
566 devpriv->dma_runs_to_end--;
567 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
568 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
570 len = devpriv->hwdmasize[0] >> 1;
573 for (i = 0; i < len; i++) {
574 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
576 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
578 devpriv->act_chanlist[devpriv->act_chanlist_pos],
579 devpriv->act_chanlist_pos);
580 pcl818_ai_cancel(dev, s);
581 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
582 comedi_event(dev, s);
586 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
588 devpriv->act_chanlist_pos++;
589 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
590 devpriv->act_chanlist_pos = 0;
592 s->async->cur_chan++;
593 if (s->async->cur_chan >= devpriv->ai_n_chan) {
594 s->async->cur_chan = 0;
595 devpriv->ai_act_scan--;
598 if (!devpriv->neverending_ai)
599 if (devpriv->ai_act_scan == 0) { /* all data sampled */
600 pcl818_ai_cancel(dev, s);
601 s->async->events |= COMEDI_CB_EOA;
602 comedi_event(dev, s);
603 /* printk("done int ai13 dma\n"); */
609 comedi_event(dev, s);
615 ==============================================================================
616 analog input dma mode 1 & 3 over RTC, 818 cards
618 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
620 struct comedi_device *dev = d;
621 struct pcl818_private *devpriv = dev->private;
622 struct comedi_subdevice *s = &dev->subdevices[0];
624 unsigned int top1, top2, i, bufptr;
626 short *dmabuf = (short *)devpriv->dmabuf[0];
629 switch (devpriv->ai_mode) {
630 case INT_TYPE_AI1_DMA_RTC:
631 case INT_TYPE_AI3_DMA_RTC:
632 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
633 mod_timer(&devpriv->rtc_irq_timer,
634 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
636 for (i = 0; i < 10; i++) {
637 top1 = get_dma_residue(devpriv->dma);
638 top2 = get_dma_residue(devpriv->dma);
645 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
647 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
649 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
651 return IRQ_HANDLED; /* exit=no new samples from last call */
653 i = devpriv->last_top_dma - 1;
654 i &= (devpriv->dmasamplsize - 1);
656 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
657 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
658 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
659 pcl818_ai_cancel(dev, s);
660 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
661 comedi_event(dev, s);
664 /* printk("r %ld ",ofs_dats); */
666 bufptr = devpriv->last_top_dma;
668 for (i = 0; i < ofs_dats; i++) {
669 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
671 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
672 (dmabuf[bufptr] & 0xf),
674 act_chanlist[devpriv->act_chanlist_pos]);
675 pcl818_ai_cancel(dev, s);
677 COMEDI_CB_EOA | COMEDI_CB_ERROR;
678 comedi_event(dev, s);
682 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
683 bufptr &= (devpriv->dmasamplsize - 1);
685 devpriv->act_chanlist_pos++;
686 if (devpriv->act_chanlist_pos >=
687 devpriv->act_chanlist_len) {
688 devpriv->act_chanlist_pos = 0;
690 s->async->cur_chan++;
691 if (s->async->cur_chan >= devpriv->ai_n_chan) {
692 s->async->cur_chan = 0;
693 devpriv->ai_act_scan--;
696 if (!devpriv->neverending_ai)
697 if (devpriv->ai_act_scan == 0) { /* all data sampled */
698 pcl818_ai_cancel(dev, s);
699 s->async->events |= COMEDI_CB_EOA;
700 comedi_event(dev, s);
701 /* printk("done int ai13 dma\n"); */
706 devpriv->last_top_dma = bufptr;
708 bufptr &= (devpriv->dmasamplsize - 1);
709 dmabuf[bufptr] = MAGIC_DMA_WORD;
710 comedi_event(dev, s);
721 ==============================================================================
722 analog input interrupt mode 1 & 3, 818HD/HG cards
724 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
726 struct comedi_device *dev = d;
727 struct pcl818_private *devpriv = dev->private;
728 struct comedi_subdevice *s = &dev->subdevices[0];
731 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
733 lo = inb(dev->iobase + PCL818_FI_STATUS);
736 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
737 pcl818_ai_cancel(dev, s);
738 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
739 comedi_event(dev, s);
744 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
745 pcl818_ai_cancel(dev, s);
746 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
747 comedi_event(dev, s);
756 for (i = 0; i < len; i++) {
757 lo = inb(dev->iobase + PCL818_FI_DATALO);
758 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
760 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
762 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
763 pcl818_ai_cancel(dev, s);
764 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
765 comedi_event(dev, s);
769 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
771 devpriv->act_chanlist_pos++;
772 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
773 devpriv->act_chanlist_pos = 0;
775 s->async->cur_chan++;
776 if (s->async->cur_chan >= devpriv->ai_n_chan) {
777 s->async->cur_chan = 0;
778 devpriv->ai_act_scan--;
781 if (!devpriv->neverending_ai)
782 if (devpriv->ai_act_scan == 0) { /* all data sampled */
783 pcl818_ai_cancel(dev, s);
784 s->async->events |= COMEDI_CB_EOA;
785 comedi_event(dev, s);
791 comedi_event(dev, s);
796 ==============================================================================
799 static irqreturn_t interrupt_pcl818(int irq, void *d)
801 struct comedi_device *dev = d;
802 struct pcl818_private *devpriv = dev->private;
804 if (!dev->attached) {
805 comedi_error(dev, "premature interrupt");
810 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
811 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
812 devpriv->ai_act_scan > 0)) &&
813 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
814 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
815 /* The cleanup from ai_cancel() has been delayed
816 until now because the card doesn't seem to like
817 being reprogrammed while a DMA transfer is in
820 struct comedi_subdevice *s = &dev->subdevices[0];
821 devpriv->ai_act_scan = 0;
822 devpriv->neverending_ai = 0;
823 pcl818_ai_cancel(dev, s);
826 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
831 switch (devpriv->ai_mode) {
832 case INT_TYPE_AI1_DMA:
833 case INT_TYPE_AI3_DMA:
834 return interrupt_pcl818_ai_mode13_dma(irq, d);
835 case INT_TYPE_AI1_INT:
836 case INT_TYPE_AI3_INT:
837 return interrupt_pcl818_ai_mode13_int(irq, d);
838 case INT_TYPE_AI1_FIFO:
839 case INT_TYPE_AI3_FIFO:
840 return interrupt_pcl818_ai_mode13_fifo(irq, d);
841 #ifdef PCL818_MODE13_AO
842 case INT_TYPE_AO1_INT:
843 case INT_TYPE_AO3_INT:
844 return interrupt_pcl818_ao_mode13_int(irq, d);
850 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
852 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
853 || (!devpriv->ai_mode)) {
854 comedi_error(dev, "bad IRQ!");
858 comedi_error(dev, "IRQ from unknown source!");
863 ==============================================================================
864 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
866 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
867 struct comedi_subdevice *s)
869 struct pcl818_private *devpriv = dev->private;
873 printk("mode13dma_int, mode: %d\n", mode);
874 disable_dma(devpriv->dma); /* disable dma */
875 bytes = devpriv->hwdmasize[0];
876 if (!devpriv->neverending_ai) {
877 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
878 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
879 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
880 devpriv->dma_runs_to_end--;
881 if (devpriv->dma_runs_to_end >= 0)
882 bytes = devpriv->hwdmasize[0];
885 devpriv->next_dma_buf = 0;
886 set_dma_mode(devpriv->dma, DMA_MODE_READ);
887 flags = claim_dma_lock();
888 clear_dma_ff(devpriv->dma);
889 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
890 set_dma_count(devpriv->dma, bytes);
891 release_dma_lock(flags);
892 enable_dma(devpriv->dma);
895 devpriv->ai_mode = INT_TYPE_AI1_DMA;
896 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
898 devpriv->ai_mode = INT_TYPE_AI3_DMA;
899 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
905 ==============================================================================
906 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
908 static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
909 struct comedi_subdevice *s)
911 struct pcl818_private *devpriv = dev->private;
915 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
916 flags = claim_dma_lock();
917 clear_dma_ff(devpriv->dma);
918 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
919 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
920 release_dma_lock(flags);
921 enable_dma(devpriv->dma);
922 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
923 pole = (short *)devpriv->dmabuf[0];
924 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
925 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
927 devpriv->rtc_freq = rtc_setfreq_irq(2048);
928 devpriv->rtc_irq_timer.expires =
929 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
930 devpriv->rtc_irq_timer.data = (unsigned long)dev;
931 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
933 add_timer(&devpriv->rtc_irq_timer);
937 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
938 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
940 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
941 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
947 ==============================================================================
948 ANALOG INPUT MODE 1 or 3, 818 cards
950 static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
951 struct comedi_subdevice *s)
953 struct pcl818_private *devpriv = dev->private;
954 struct comedi_cmd *cmd = &s->async->cmd;
955 int divisor1 = 0, divisor2 = 0;
958 dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode()\n");
959 if ((!dev->irq) && (!devpriv->dma_rtc)) {
960 comedi_error(dev, "IRQ not defined!");
964 if (devpriv->irq_blocked)
967 start_pacer(dev, -1, 0, 0); /* stop pacer */
969 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
973 setup_channel_list(dev, s, devpriv->ai_chanlist,
974 devpriv->ai_n_chan, seglen);
978 devpriv->ai_act_scan = devpriv->ai_scans;
979 devpriv->ai_act_chan = 0;
980 devpriv->irq_blocked = 1;
981 devpriv->irq_was_now_closed = 0;
982 devpriv->neverending_ai = 0;
983 devpriv->act_chanlist_pos = 0;
984 devpriv->dma_runs_to_end = 0;
986 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
987 devpriv->neverending_ai = 1; /* well, user want neverending */
990 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
991 &divisor2, &cmd->convert_arg,
993 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
1003 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1005 switch (devpriv->dma) {
1008 if (devpriv->dma_rtc == 0)
1009 pcl818_ai_mode13dma_int(mode, dev, s);
1012 pcl818_ai_mode13dma_rtc(mode, dev, s);
1019 if (!devpriv->usefifo) {
1021 /* printk("IRQ\n"); */
1023 devpriv->ai_mode = INT_TYPE_AI1_INT;
1025 outb(0x83 | (dev->irq << 4),
1026 dev->iobase + PCL818_CONTROL);
1028 devpriv->ai_mode = INT_TYPE_AI3_INT;
1030 outb(0x82 | (dev->irq << 4),
1031 dev->iobase + PCL818_CONTROL);
1036 outb(1, dev->iobase + PCL818_FI_ENABLE);
1038 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1040 outb(0x03, dev->iobase + PCL818_CONTROL);
1042 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1043 outb(0x02, dev->iobase + PCL818_CONTROL);
1048 start_pacer(dev, mode, divisor1, divisor2);
1051 switch (devpriv->ai_mode) {
1052 case INT_TYPE_AI1_DMA_RTC:
1053 case INT_TYPE_AI3_DMA_RTC:
1054 set_rtc_irq_bit(1); /* start RTC */
1058 dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode() end\n");
1064 ==============================================================================
1065 ANALOG OUTPUT MODE 1 or 3, 818 cards
1067 #ifdef PCL818_MODE13_AO
1068 static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1069 struct comedi_subdevice *s, comedi_trig *it)
1071 struct pcl818_private *devpriv = dev->private;
1072 int divisor1 = 0, divisor2 = 0;
1075 comedi_error(dev, "IRQ not defined!");
1079 if (devpriv->irq_blocked)
1082 start_pacer(dev, -1, 0, 0); /* stop pacer */
1084 devpriv->int13_act_scan = it->n;
1085 devpriv->int13_act_chan = 0;
1086 devpriv->irq_blocked = 1;
1087 devpriv->irq_was_now_closed = 0;
1088 devpriv->neverending_ai = 0;
1089 devpriv->act_chanlist_pos = 0;
1092 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1093 &divisor2, &it->trigvar,
1094 TRIG_ROUND_NEAREST);
1095 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1099 if (divisor2 == 1) {
1105 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1107 devpriv->int818_mode = INT_TYPE_AO1_INT;
1108 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1110 devpriv->int818_mode = INT_TYPE_AO3_INT;
1111 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1114 start_pacer(dev, mode, divisor1, divisor2);
1120 ==============================================================================
1121 ANALOG OUTPUT MODE 1, 818 cards
1123 static int pcl818_ao_mode1(struct comedi_device *dev,
1124 struct comedi_subdevice *s, comedi_trig *it)
1126 return pcl818_ao_mode13(1, dev, s, it);
1130 ==============================================================================
1131 ANALOG OUTPUT MODE 3, 818 cards
1133 static int pcl818_ao_mode3(struct comedi_device *dev,
1134 struct comedi_subdevice *s, comedi_trig *it)
1136 return pcl818_ao_mode13(3, dev, s, it);
1142 ==============================================================================
1143 Start/stop pacer onboard pacer
1145 static void start_pacer(struct comedi_device *dev, int mode,
1146 unsigned int divisor1, unsigned int divisor2)
1148 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1149 outb(0x74, dev->iobase + PCL818_CTRCTL);
1153 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1154 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1155 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1156 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1161 ==============================================================================
1162 Check if channel list from user is builded correctly
1163 If it's ok, then program scan/gain logic
1165 static int check_channel_list(struct comedi_device *dev,
1166 struct comedi_subdevice *s,
1167 unsigned int *chanlist, unsigned int n_chan)
1169 unsigned int chansegment[16];
1170 unsigned int i, nowmustbechan, seglen, segpos;
1172 /* correct channel and range number check itself comedi/range.c */
1174 comedi_error(dev, "range/channel list is empty!");
1179 /* first channel is every time ok */
1180 chansegment[0] = chanlist[0];
1181 /* build part of chanlist */
1182 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1184 /* printk("%d. %d * %d\n",i,
1185 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1187 /* we detect loop, this must by finish */
1189 if (chanlist[0] == chanlist[i])
1192 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1193 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
1195 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1196 dev->minor, i, CR_CHAN(chanlist[i]),
1197 nowmustbechan, CR_CHAN(chanlist[0]));
1200 /* well, this is next correct channel in list */
1201 chansegment[i] = chanlist[i];
1204 /* check whole chanlist */
1205 for (i = 0, segpos = 0; i < n_chan; i++) {
1206 /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */
1207 if (chanlist[i] != chansegment[i % seglen]) {
1209 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1210 dev->minor, i, CR_CHAN(chansegment[i]),
1211 CR_RANGE(chansegment[i]),
1212 CR_AREF(chansegment[i]),
1213 CR_CHAN(chanlist[i % seglen]),
1214 CR_RANGE(chanlist[i % seglen]),
1215 CR_AREF(chansegment[i % seglen]));
1216 return 0; /* chan/gain list is strange */
1222 printk("check_channel_list: seglen %d\n", seglen);
1226 static void setup_channel_list(struct comedi_device *dev,
1227 struct comedi_subdevice *s,
1228 unsigned int *chanlist, unsigned int n_chan,
1229 unsigned int seglen)
1231 struct pcl818_private *devpriv = dev->private;
1234 devpriv->act_chanlist_len = seglen;
1235 devpriv->act_chanlist_pos = 0;
1237 for (i = 0; i < seglen; i++) { /* store range list to card */
1238 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1239 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1240 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1245 /* select channel interval to scan */
1246 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1248 dev->iobase + PCL818_MUX);
1252 ==============================================================================
1253 Check if board is switched to SE (1) or DIFF(0) mode
1255 static int check_single_ended(unsigned int port)
1257 if (inb(port + PCL818_STATUS) & 0x20)
1263 ==============================================================================
1265 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1266 struct comedi_cmd *cmd)
1268 const struct pcl818_board *board = comedi_board(dev);
1269 struct pcl818_private *devpriv = dev->private;
1271 int tmp, divisor1 = 0, divisor2 = 0;
1273 /* Step 1 : check if triggers are trivially valid */
1275 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
1276 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
1277 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
1278 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1279 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1284 /* Step 2a : make sure trigger sources are unique */
1286 err |= cfc_check_trigger_is_unique(cmd->convert_src);
1287 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1289 /* Step 2b : and mutually compatible */
1294 /* Step 3: check if arguments are trivially valid */
1296 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
1297 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
1299 if (cmd->convert_src == TRIG_TIMER)
1300 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
1303 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
1305 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1307 if (cmd->stop_src == TRIG_COUNT)
1308 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1309 else /* TRIG_NONE */
1310 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
1315 /* step 4: fix up any arguments */
1317 if (cmd->convert_src == TRIG_TIMER) {
1318 tmp = cmd->convert_arg;
1319 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1320 &divisor2, &cmd->convert_arg,
1321 cmd->flags & TRIG_ROUND_MASK);
1322 if (cmd->convert_arg < board->ns_min)
1323 cmd->convert_arg = board->ns_min;
1324 if (tmp != cmd->convert_arg)
1331 /* step 5: complain about special chanlist considerations */
1333 if (cmd->chanlist) {
1334 if (!check_channel_list(dev, s, cmd->chanlist,
1336 return 5; /* incorrect channels list */
1343 ==============================================================================
1345 static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1347 struct pcl818_private *devpriv = dev->private;
1348 struct comedi_cmd *cmd = &s->async->cmd;
1351 dev_dbg(dev->class_dev, "pcl818_ai_cmd()\n");
1352 devpriv->ai_n_chan = cmd->chanlist_len;
1353 devpriv->ai_chanlist = cmd->chanlist;
1354 devpriv->ai_flags = cmd->flags;
1355 devpriv->ai_data_len = s->async->prealloc_bufsz;
1356 devpriv->ai_data = s->async->prealloc_buf;
1357 devpriv->ai_timer1 = 0;
1358 devpriv->ai_timer2 = 0;
1360 if (cmd->stop_src == TRIG_COUNT)
1361 devpriv->ai_scans = cmd->stop_arg;
1363 devpriv->ai_scans = 0;
1365 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1366 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
1367 devpriv->ai_timer1 = cmd->convert_arg;
1368 retval = pcl818_ai_cmd_mode(1, dev, s);
1369 dev_dbg(dev->class_dev, "pcl818_ai_cmd() end\n");
1372 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1373 return pcl818_ai_cmd_mode(3, dev, s);
1381 ==============================================================================
1382 cancel any mode 1-4 AI
1384 static int pcl818_ai_cancel(struct comedi_device *dev,
1385 struct comedi_subdevice *s)
1387 struct pcl818_private *devpriv = dev->private;
1389 if (devpriv->irq_blocked > 0) {
1390 dev_dbg(dev->class_dev, "pcl818_ai_cancel()\n");
1391 devpriv->irq_was_now_closed = 1;
1393 switch (devpriv->ai_mode) {
1395 case INT_TYPE_AI1_DMA_RTC:
1396 case INT_TYPE_AI3_DMA_RTC:
1397 set_rtc_irq_bit(0); /* stop RTC */
1398 del_timer(&devpriv->rtc_irq_timer);
1400 case INT_TYPE_AI1_DMA:
1401 case INT_TYPE_AI3_DMA:
1402 if (devpriv->neverending_ai ||
1403 (!devpriv->neverending_ai &&
1404 devpriv->ai_act_scan > 0)) {
1405 /* wait for running dma transfer to end, do cleanup in interrupt */
1408 disable_dma(devpriv->dma);
1409 case INT_TYPE_AI1_INT:
1410 case INT_TYPE_AI3_INT:
1411 case INT_TYPE_AI1_FIFO:
1412 case INT_TYPE_AI3_FIFO:
1413 #ifdef PCL818_MODE13_AO
1414 case INT_TYPE_AO1_INT:
1415 case INT_TYPE_AO3_INT:
1417 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1419 start_pacer(dev, -1, 0, 0);
1420 outb(0, dev->iobase + PCL818_AD_LO);
1421 inb(dev->iobase + PCL818_AD_LO);
1422 inb(dev->iobase + PCL818_AD_HI);
1423 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1424 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1425 if (devpriv->usefifo) { /* FIFO shutdown */
1426 outb(0, dev->iobase + PCL818_FI_INTCLR);
1427 outb(0, dev->iobase + PCL818_FI_FLUSH);
1428 outb(0, dev->iobase + PCL818_FI_ENABLE);
1430 devpriv->irq_blocked = 0;
1431 devpriv->last_int_sub = s;
1432 devpriv->neverending_ai = 0;
1433 devpriv->ai_mode = 0;
1434 devpriv->irq_was_now_closed = 0;
1440 dev_dbg(dev->class_dev, "pcl818_ai_cancel() end\n");
1445 ==============================================================================
1448 static int pcl818_check(unsigned long iobase)
1450 outb(0x00, iobase + PCL818_MUX);
1452 if (inb(iobase + PCL818_MUX) != 0x00)
1453 return 1; /* there isn't card */
1454 outb(0x55, iobase + PCL818_MUX);
1456 if (inb(iobase + PCL818_MUX) != 0x55)
1457 return 1; /* there isn't card */
1458 outb(0x00, iobase + PCL818_MUX);
1460 outb(0x18, iobase + PCL818_CONTROL);
1462 if (inb(iobase + PCL818_CONTROL) != 0x18)
1463 return 1; /* there isn't card */
1464 return 0; /* ok, card exist */
1468 ==============================================================================
1469 reset whole PCL-818 cards
1471 static void pcl818_reset(struct comedi_device *dev)
1473 const struct pcl818_board *board = comedi_board(dev);
1474 struct pcl818_private *devpriv = dev->private;
1476 if (devpriv->usefifo) { /* FIFO shutdown */
1477 outb(0, dev->iobase + PCL818_FI_INTCLR);
1478 outb(0, dev->iobase + PCL818_FI_FLUSH);
1479 outb(0, dev->iobase + PCL818_FI_ENABLE);
1481 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
1482 outb(0, dev->iobase + PCL818_DA_HI);
1484 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
1485 outb(0, dev->iobase + PCL818_DO_LO);
1487 outb(0, dev->iobase + PCL818_CONTROL);
1488 outb(0, dev->iobase + PCL818_CNTENABLE);
1489 outb(0, dev->iobase + PCL818_MUX);
1490 outb(0, dev->iobase + PCL818_CLRINT);
1491 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1492 outb(0x70, dev->iobase + PCL818_CTRCTL);
1493 outb(0x30, dev->iobase + PCL818_CTRCTL);
1494 if (board->is_818) {
1495 outb(0, dev->iobase + PCL818_RANGE);
1497 outb(0, dev->iobase + PCL718_DA2_LO);
1498 outb(0, dev->iobase + PCL718_DA2_HI);
1504 ==============================================================================
1505 Enable(1)/disable(0) periodic interrupts from RTC
1507 static int set_rtc_irq_bit(unsigned char bit)
1510 unsigned long flags;
1514 if (RTC_timer_lock > 1)
1518 if (RTC_timer_lock < 0)
1520 if (RTC_timer_lock > 0)
1526 val = CMOS_READ(RTC_CONTROL);
1532 CMOS_WRITE(val, RTC_CONTROL);
1533 CMOS_READ(RTC_INTR_FLAGS);
1534 restore_flags(flags);
1539 ==============================================================================
1540 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1542 static void rtc_dropped_irq(unsigned long data)
1544 struct comedi_device *dev = (void *)data;
1545 struct pcl818_private *devpriv = dev->private;
1546 unsigned long flags, tmp;
1548 switch (devpriv->int818_mode) {
1549 case INT_TYPE_AI1_DMA_RTC:
1550 case INT_TYPE_AI3_DMA_RTC:
1551 mod_timer(&devpriv->rtc_irq_timer,
1552 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1555 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1556 restore_flags(flags);
1562 ==============================================================================
1563 Set frequency of interrupts from RTC
1565 static int rtc_setfreq_irq(int freq)
1570 unsigned long flags;
1577 while (freq > (1 << tmp))
1580 rtc_freq = 1 << tmp;
1584 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1586 CMOS_WRITE(val, RTC_FREQ_SELECT);
1587 restore_flags(flags);
1592 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1594 const struct pcl818_board *board = comedi_board(dev);
1595 struct pcl818_private *devpriv;
1599 unsigned long pages;
1600 struct comedi_subdevice *s;
1602 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1605 dev->private = devpriv;
1607 devpriv->io_range = board->io_range;
1608 if ((board->fifo) && (it->options[2] == -1)) {
1609 /* we've board with FIFO and we want to use FIFO */
1610 devpriv->io_range = PCLx1xFIFO_RANGE;
1611 devpriv->usefifo = 1;
1613 ret = comedi_request_region(dev, it->options[0], devpriv->io_range);
1617 if (pcl818_check(dev->iobase)) {
1618 comedi_error(dev, "I can't detect board. FAIL!\n");
1624 if (board->IRQbits != 0) { /* board support IRQ */
1625 irq = it->options[1];
1626 if (irq) { /* we want to use IRQ */
1627 if (((1 << irq) & board->IRQbits) == 0) {
1629 (", IRQ %u is out of allowed range, DISABLING IT",
1631 irq = 0; /* Bad IRQ */
1633 if (request_irq(irq, interrupt_pcl818, 0,
1634 dev->board_name, dev)) {
1636 (", unable to allocate IRQ %u, DISABLING IT",
1638 irq = 0; /* Can't use IRQ */
1640 printk(KERN_DEBUG "irq=%u", irq);
1648 devpriv->irq_free = 1; /* 1=we have allocated irq */
1650 devpriv->irq_free = 0;
1652 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1653 devpriv->ai_mode = 0; /* mode of irq */
1656 /* grab RTC for DMA operations */
1657 devpriv->dma_rtc = 0;
1658 if (it->options[2] > 0) { /* we want to use DMA */
1659 if (RTC_lock == 0) {
1660 ret = __comedi_request_resource(dev, RTC_PORT(0),
1665 devpriv->rtc_iobase = RTC_PORT(0);
1666 devpriv->rtc_iosize = RTC_IO_EXTENT;
1668 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
1669 "pcl818 DMA (RTC)", dev)) {
1670 devpriv->dma_rtc = 1;
1671 devpriv->rtc_irq = RTC_IRQ;
1672 printk(KERN_DEBUG "dma_irq=%u", devpriv->rtc_irq);
1675 if (RTC_lock == 0) {
1676 if (devpriv->rtc_iobase)
1677 release_region(devpriv->rtc_iobase,
1678 devpriv->rtc_iosize);
1680 devpriv->rtc_iobase = 0;
1681 devpriv->rtc_iosize = 0;
1690 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1691 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1692 if (board->DMAbits != 0) { /* board support DMA */
1693 dma = it->options[2];
1695 goto no_dma; /* DMA disabled */
1696 if (((1 << dma) & board->DMAbits) == 0) {
1697 printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
1698 return -EINVAL; /* Bad DMA */
1700 ret = request_dma(dma, dev->board_name);
1702 return -EBUSY; /* DMA isn't free */
1704 pages = 2; /* we need 16KB */
1705 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1706 if (!devpriv->dmabuf[0])
1707 /* maybe experiment with try_to_free_pages() will help .... */
1708 return -EBUSY; /* no buffer :-( */
1709 devpriv->dmapages[0] = pages;
1710 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1711 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1712 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1713 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1714 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1715 if (!devpriv->dmabuf[1])
1717 devpriv->dmapages[1] = pages;
1718 devpriv->hwdmaptr[1] =
1719 virt_to_bus((void *)devpriv->dmabuf[1]);
1720 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1726 ret = comedi_alloc_subdevices(dev, 4);
1730 s = &dev->subdevices[0];
1731 if (!board->n_aichan_se) {
1732 s->type = COMEDI_SUBD_UNUSED;
1734 s->type = COMEDI_SUBD_AI;
1735 devpriv->sub_ai = s;
1736 s->subdev_flags = SDF_READABLE;
1737 if (check_single_ended(dev->iobase)) {
1738 s->n_chan = board->n_aichan_se;
1739 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1740 printk(", %dchans S.E. DAC", s->n_chan);
1742 s->n_chan = board->n_aichan_diff;
1743 s->subdev_flags |= SDF_DIFF;
1744 printk(", %dchans DIFF DAC", s->n_chan);
1746 s->maxdata = board->ai_maxdata;
1747 s->len_chanlist = s->n_chan;
1748 s->range_table = board->ai_range_type;
1749 s->cancel = pcl818_ai_cancel;
1750 s->insn_read = pcl818_ai_insn_read;
1751 if ((irq) || (devpriv->dma_rtc)) {
1752 dev->read_subdev = s;
1753 s->subdev_flags |= SDF_CMD_READ;
1754 s->do_cmdtest = ai_cmdtest;
1757 if (board->is_818) {
1758 if ((it->options[4] == 1) || (it->options[4] == 10))
1759 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
1761 switch (it->options[4]) {
1763 s->range_table = &range_bipolar10;
1766 s->range_table = &range_bipolar5;
1769 s->range_table = &range_bipolar2_5;
1772 s->range_table = &range718_bipolar1;
1775 s->range_table = &range718_bipolar0_5;
1778 s->range_table = &range_unipolar10;
1781 s->range_table = &range_unipolar5;
1784 s->range_table = &range718_unipolar2;
1787 s->range_table = &range718_unipolar1;
1790 s->range_table = &range_unknown;
1796 s = &dev->subdevices[1];
1797 if (!board->n_aochan) {
1798 s->type = COMEDI_SUBD_UNUSED;
1800 s->type = COMEDI_SUBD_AO;
1801 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1802 s->n_chan = board->n_aochan;
1803 s->maxdata = board->ao_maxdata;
1804 s->len_chanlist = board->n_aochan;
1805 s->range_table = board->ao_range_type;
1806 s->insn_read = pcl818_ao_insn_read;
1807 s->insn_write = pcl818_ao_insn_write;
1809 #ifdef PCL818_MODE13_AO
1811 s->trig[1] = pcl818_ao_mode1;
1812 s->trig[3] = pcl818_ao_mode3;
1816 if (board->is_818) {
1817 if ((it->options[4] == 1) || (it->options[4] == 10))
1818 s->range_table = &range_unipolar10;
1819 if (it->options[4] == 2)
1820 s->range_table = &range_unknown;
1822 if ((it->options[5] == 1) || (it->options[5] == 10))
1823 s->range_table = &range_unipolar10;
1824 if (it->options[5] == 2)
1825 s->range_table = &range_unknown;
1829 s = &dev->subdevices[2];
1830 if (!board->n_dichan) {
1831 s->type = COMEDI_SUBD_UNUSED;
1833 s->type = COMEDI_SUBD_DI;
1834 s->subdev_flags = SDF_READABLE;
1835 s->n_chan = board->n_dichan;
1837 s->len_chanlist = board->n_dichan;
1838 s->range_table = &range_digital;
1839 s->insn_bits = pcl818_di_insn_bits;
1842 s = &dev->subdevices[3];
1843 if (!board->n_dochan) {
1844 s->type = COMEDI_SUBD_UNUSED;
1846 s->type = COMEDI_SUBD_DO;
1847 s->subdev_flags = SDF_WRITABLE;
1848 s->n_chan = board->n_dochan;
1850 s->len_chanlist = board->n_dochan;
1851 s->range_table = &range_digital;
1852 s->insn_bits = pcl818_do_insn_bits;
1855 /* select 1/10MHz oscilator */
1856 if ((it->options[3] == 0) || (it->options[3] == 10))
1857 devpriv->i8253_osc_base = 100;
1859 devpriv->i8253_osc_base = 1000;
1861 /* max sampling speed */
1862 devpriv->ns_min = board->ns_min;
1864 if (!board->is_818) {
1865 if ((it->options[6] == 1) || (it->options[6] == 100))
1866 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1876 static void pcl818_detach(struct comedi_device *dev)
1878 struct pcl818_private *devpriv = dev->private;
1881 pcl818_ai_cancel(dev, devpriv->sub_ai);
1884 free_dma(devpriv->dma);
1885 if (devpriv->dmabuf[0])
1886 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1887 if (devpriv->dmabuf[1])
1888 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1890 if (devpriv->rtc_irq)
1891 free_irq(devpriv->rtc_irq, dev);
1892 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1893 if (devpriv->rtc_iobase)
1894 release_region(devpriv->rtc_iobase,
1895 devpriv->rtc_iosize);
1897 if (devpriv->dma_rtc)
1902 free_irq(dev->irq, dev);
1903 comedi_legacy_detach(dev);
1906 static const struct pcl818_board boardtypes[] = {
1907 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
1908 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1909 0x0a, 0xfff, 0xfff, 0, 1},
1910 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1911 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1912 0x0a, 0xfff, 0xfff, 0, 1},
1913 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
1914 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1915 0x0a, 0xfff, 0xfff, 1, 1},
1916 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
1917 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1918 0x0a, 0xfff, 0xfff, 1, 1},
1919 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
1920 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1921 0x0a, 0xfff, 0xfff, 0, 1},
1922 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
1923 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1924 0x0a, 0xfff, 0xfff, 0, 0},
1926 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
1927 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
1928 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
1931 static struct comedi_driver pcl818_driver = {
1932 .driver_name = "pcl818",
1933 .module = THIS_MODULE,
1934 .attach = pcl818_attach,
1935 .detach = pcl818_detach,
1936 .board_name = &boardtypes[0].name,
1937 .num_names = ARRAY_SIZE(boardtypes),
1938 .offset = sizeof(struct pcl818_board),
1940 module_comedi_driver(pcl818_driver);
1942 MODULE_AUTHOR("Comedi http://www.comedi.org");
1943 MODULE_DESCRIPTION("Comedi low-level driver");
1944 MODULE_LICENSE("GPL");