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>
112 /* #define PCL818_MODE13_AO 1 */
114 /* boards constants */
116 #define boardPCL818L 0
117 #define boardPCL818H 1
118 #define boardPCL818HD 2
119 #define boardPCL818HG 3
120 #define boardPCL818 4
121 #define boardPCL718 5
124 #define PCLx1x_RANGE 16
125 /* IO space len if we use FIFO */
126 #define PCLx1xFIFO_RANGE 32
128 /* W: clear INT request */
129 #define PCL818_CLRINT 8
130 /* R: return status byte */
131 #define PCL818_STATUS 8
132 /* R: A/D high byte W: A/D range control */
133 #define PCL818_RANGE 1
134 /* R: next mux scan channel W: mux scan channel & range control pointer */
136 /* R/W: operation control register */
137 #define PCL818_CONTROL 9
138 /* W: counter enable */
139 #define PCL818_CNTENABLE 10
141 /* R: low byte of A/D W: soft A/D trigger */
142 #define PCL818_AD_LO 0
143 /* R: high byte of A/D W: A/D range control */
144 #define PCL818_AD_HI 1
145 /* W: D/A low&high byte */
146 #define PCL818_DA_LO 4
147 #define PCL818_DA_HI 5
148 /* R: low&high byte of DI */
149 #define PCL818_DI_LO 3
150 #define PCL818_DI_HI 11
151 /* W: low&high byte of DO */
152 #define PCL818_DO_LO 3
153 #define PCL818_DO_HI 11
154 /* W: PCL718 second D/A */
155 #define PCL718_DA2_LO 6
156 #define PCL718_DA2_HI 7
158 #define PCL818_CTR0 12
159 #define PCL818_CTR1 13
160 #define PCL818_CTR2 14
161 /* W: counter control */
162 #define PCL818_CTRCTL 15
164 /* W: fifo enable/disable */
165 #define PCL818_FI_ENABLE 6
166 /* W: fifo interrupt clear */
167 #define PCL818_FI_INTCLR 20
168 /* W: fifo interrupt clear */
169 #define PCL818_FI_FLUSH 25
171 #define PCL818_FI_STATUS 25
172 /* R: one record from FIFO */
173 #define PCL818_FI_DATALO 23
174 #define PCL818_FI_DATAHI 23
176 /* type of interrupt handler */
177 #define INT_TYPE_AI1_INT 1
178 #define INT_TYPE_AI1_DMA 2
179 #define INT_TYPE_AI1_FIFO 3
180 #define INT_TYPE_AI3_INT 4
181 #define INT_TYPE_AI3_DMA 5
182 #define INT_TYPE_AI3_FIFO 6
183 #ifdef PCL818_MODE13_AO
184 #define INT_TYPE_AO1_INT 7
185 #define INT_TYPE_AO3_INT 8
190 #define INT_TYPE_AI1_DMA_RTC 9
191 #define INT_TYPE_AI3_DMA_RTC 10
194 #define RTC_IO_EXTENT 0x10
197 #define MAGIC_DMA_WORD 0x5a5a
199 static const struct comedi_lrange range_pcl818h_ai = { 9, {
212 static const struct comedi_lrange range_pcl818hg_ai = { 10, {
228 static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
236 static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
244 static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
245 static const struct comedi_lrange range718_bipolar0_5 =
246 { 1, {BIP_RANGE(0.5),} };
247 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
248 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
250 static int pcl818_attach(struct comedi_device *dev,
251 struct comedi_devconfig *it);
252 static int pcl818_detach(struct comedi_device *dev);
255 static int RTC_lock = 0; /* RTC lock */
256 static int RTC_timer_lock = 0; /* RTC int lock */
259 struct pcl818_board {
261 const char *name; /* driver name */
262 int n_ranges; /* len of range list */
263 int n_aichan_se; /* num of A/D chans in single ended mode */
264 int n_aichan_diff; /* num of A/D chans in diferencial mode */
265 unsigned int ns_min; /* minimal allowed delay between samples (in ns) */
266 int n_aochan; /* num of D/A chans */
267 int n_dichan; /* num of DI chans */
268 int n_dochan; /* num of DO chans */
269 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
270 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
271 unsigned int io_range; /* len of IO space */
272 unsigned int IRQbits; /* allowed interrupts */
273 unsigned int DMAbits; /* allowed DMA chans */
274 int ai_maxdata; /* maxdata for A/D */
275 int ao_maxdata; /* maxdata for D/A */
276 unsigned char fifo; /* 1=board has FIFO */
280 static const struct pcl818_board boardtypes[] = {
281 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
282 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
283 0x0a, 0xfff, 0xfff, 0, 1},
284 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
285 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
286 0x0a, 0xfff, 0xfff, 0, 1},
287 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
288 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
289 0x0a, 0xfff, 0xfff, 1, 1},
290 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
291 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
292 0x0a, 0xfff, 0xfff, 1, 1},
293 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
294 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
295 0x0a, 0xfff, 0xfff, 0, 1},
296 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
297 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
298 0x0a, 0xfff, 0xfff, 0, 0},
300 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
301 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
302 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
305 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
307 static struct comedi_driver driver_pcl818 = {
308 .driver_name = "pcl818",
309 .module = THIS_MODULE,
310 .attach = pcl818_attach,
311 .detach = pcl818_detach,
312 .board_name = &boardtypes[0].name,
313 .num_names = n_boardtypes,
314 .offset = sizeof(struct pcl818_board),
317 static int __init driver_pcl818_init_module(void)
319 return comedi_driver_register(&driver_pcl818);
322 static void __exit driver_pcl818_cleanup_module(void)
324 comedi_driver_unregister(&driver_pcl818);
327 module_init(driver_pcl818_init_module);
328 module_exit(driver_pcl818_cleanup_module);
330 struct pcl818_private {
332 unsigned int dma; /* used DMA, 0=don't use DMA */
333 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
334 unsigned int io_range;
336 unsigned long rtc_iobase; /* RTC port region */
337 unsigned int rtc_iosize;
338 unsigned int rtc_irq;
339 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
340 unsigned long rtc_freq; /* RTC int freq */
341 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
343 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
344 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
345 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
346 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
347 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
348 unsigned int last_top_dma; /* DMA pointer in last RTC int */
349 int next_dma_buf; /* which DMA buffer will be used next round */
350 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
351 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
352 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
353 unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
354 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
355 int irq_free; /* 1=have allocated IRQ */
356 int irq_blocked; /* 1=IRQ now uses any subdev */
357 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
358 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
359 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
360 int ai_act_scan; /* how many scans we finished */
361 int ai_act_chan; /* actual position in actual scan */
362 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
363 unsigned int act_chanlist_len; /* how long is actual MUX list */
364 unsigned int act_chanlist_pos; /* actual position in MUX list */
365 unsigned int ai_scans; /* len of scanlist */
366 unsigned int ai_n_chan; /* how many channels is measured */
367 unsigned int *ai_chanlist; /* actaul chanlist */
368 unsigned int ai_flags; /* flaglist */
369 unsigned int ai_data_len; /* len of data buffer */
370 short *ai_data; /* data buffer */
371 unsigned int ai_timer1; /* timers */
372 unsigned int ai_timer2;
373 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
374 unsigned char usefifo; /* 1=use fifo */
375 unsigned int ao_readback[2];
378 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
379 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
382 #define devpriv ((struct pcl818_private *)dev->private)
383 #define this_board ((const struct pcl818_board *)dev->board_ptr)
386 ==============================================================================
388 static void setup_channel_list(struct comedi_device *dev,
389 struct comedi_subdevice *s,
390 unsigned int *chanlist, unsigned int n_chan,
391 unsigned int seglen);
392 static int check_channel_list(struct comedi_device *dev,
393 struct comedi_subdevice *s,
394 unsigned int *chanlist, unsigned int n_chan);
396 static int pcl818_ai_cancel(struct comedi_device *dev,
397 struct comedi_subdevice *s);
398 static void start_pacer(struct comedi_device *dev, int mode,
399 unsigned int divisor1, unsigned int divisor2);
402 static int set_rtc_irq_bit(unsigned char bit);
403 static void rtc_dropped_irq(unsigned long data);
404 static int rtc_setfreq_irq(int freq);
408 ==============================================================================
409 ANALOG INPUT MODE0, 818 cards, slow version
411 static int pcl818_ai_insn_read(struct comedi_device *dev,
412 struct comedi_subdevice *s,
413 struct comedi_insn *insn, unsigned int *data)
418 /* software trigger, DMA and INT off */
419 outb(0, dev->iobase + PCL818_CONTROL);
422 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
425 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
427 for (n = 0; n < insn->n; n++) {
429 /* clear INT (conversion end) flag */
430 outb(0, dev->iobase + PCL818_CLRINT);
432 /* start conversion */
433 outb(0, dev->iobase + PCL818_AD_LO);
437 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
441 comedi_error(dev, "A/D insn timeout");
442 /* clear INT (conversion end) flag */
443 outb(0, dev->iobase + PCL818_CLRINT);
447 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
448 (inb(dev->iobase + PCL818_AD_LO) >> 4));
455 ==============================================================================
456 ANALOG OUTPUT MODE0, 818 cards
457 only one sample per call is supported
459 static int pcl818_ao_insn_read(struct comedi_device *dev,
460 struct comedi_subdevice *s,
461 struct comedi_insn *insn, unsigned int *data)
464 int chan = CR_CHAN(insn->chanspec);
466 for (n = 0; n < insn->n; n++) {
467 data[n] = devpriv->ao_readback[chan];
473 static int pcl818_ao_insn_write(struct comedi_device *dev,
474 struct comedi_subdevice *s,
475 struct comedi_insn *insn, unsigned int *data)
478 int chan = CR_CHAN(insn->chanspec);
480 for (n = 0; n < insn->n; n++) {
481 devpriv->ao_readback[chan] = data[n];
482 outb((data[n] & 0x000f) << 4, dev->iobase +
483 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
484 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
485 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
492 ==============================================================================
493 DIGITAL INPUT MODE0, 818 cards
495 only one sample per call is supported
497 static int pcl818_di_insn_bits(struct comedi_device *dev,
498 struct comedi_subdevice *s,
499 struct comedi_insn *insn, unsigned int *data)
504 data[1] = inb(dev->iobase + PCL818_DI_LO) |
505 (inb(dev->iobase + PCL818_DI_HI) << 8);
511 ==============================================================================
512 DIGITAL OUTPUT MODE0, 818 cards
514 only one sample per call is supported
516 static int pcl818_do_insn_bits(struct comedi_device *dev,
517 struct comedi_subdevice *s,
518 struct comedi_insn *insn, unsigned int *data)
523 s->state &= ~data[0];
524 s->state |= (data[0] & data[1]);
526 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
527 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
535 ==============================================================================
536 analog input interrupt mode 1 & 3, 818 cards
537 one sample per interrupt version
539 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
541 struct comedi_device *dev = d;
542 struct comedi_subdevice *s = dev->subdevices + 0;
544 int timeout = 50; /* wait max 50us */
547 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
551 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
552 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
553 pcl818_ai_cancel(dev, s);
554 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
555 comedi_event(dev, s);
559 low = inb(dev->iobase + PCL818_AD_LO);
560 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
561 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
563 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
565 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
567 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
568 pcl818_ai_cancel(dev, s);
569 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
570 comedi_event(dev, s);
573 devpriv->act_chanlist_pos++;
574 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
575 devpriv->act_chanlist_pos = 0;
577 s->async->cur_chan++;
578 if (s->async->cur_chan >= devpriv->ai_n_chan) {
580 s->async->cur_chan = 0;
581 devpriv->ai_act_scan--;
584 if (!devpriv->neverending_ai) {
585 if (devpriv->ai_act_scan == 0) { /* all data sampled */
586 pcl818_ai_cancel(dev, s);
587 s->async->events |= COMEDI_CB_EOA;
590 comedi_event(dev, s);
595 ==============================================================================
596 analog input dma mode 1 & 3, 818 cards
598 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
600 struct comedi_device *dev = d;
601 struct comedi_subdevice *s = dev->subdevices + 0;
606 disable_dma(devpriv->dma);
607 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
608 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
609 set_dma_mode(devpriv->dma, DMA_MODE_READ);
610 flags = claim_dma_lock();
611 set_dma_addr(devpriv->dma,
612 devpriv->hwdmaptr[devpriv->next_dma_buf]);
613 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
614 set_dma_count(devpriv->dma,
615 devpriv->hwdmasize[devpriv->
618 set_dma_count(devpriv->dma, devpriv->last_dma_run);
620 release_dma_lock(flags);
621 enable_dma(devpriv->dma);
623 printk("comedi: A/D mode1/3 IRQ \n");
625 devpriv->dma_runs_to_end--;
626 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
627 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
629 len = devpriv->hwdmasize[0] >> 1;
632 for (i = 0; i < len; i++) {
633 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
635 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
637 devpriv->act_chanlist[devpriv->act_chanlist_pos],
638 devpriv->act_chanlist_pos);
639 pcl818_ai_cancel(dev, s);
640 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
641 comedi_event(dev, s);
645 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
647 devpriv->act_chanlist_pos++;
648 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
649 devpriv->act_chanlist_pos = 0;
651 s->async->cur_chan++;
652 if (s->async->cur_chan >= devpriv->ai_n_chan) {
653 s->async->cur_chan = 0;
654 devpriv->ai_act_scan--;
657 if (!devpriv->neverending_ai)
658 if (devpriv->ai_act_scan == 0) { /* all data sampled */
659 pcl818_ai_cancel(dev, s);
660 s->async->events |= COMEDI_CB_EOA;
661 comedi_event(dev, s);
662 /* printk("done int ai13 dma\n"); */
668 comedi_event(dev, s);
674 ==============================================================================
675 analog input dma mode 1 & 3 over RTC, 818 cards
677 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
679 struct comedi_device *dev = d;
680 struct comedi_subdevice *s = dev->subdevices + 0;
682 unsigned int top1, top2, i, bufptr;
684 short *dmabuf = (short *)devpriv->dmabuf[0];
687 switch (devpriv->ai_mode) {
688 case INT_TYPE_AI1_DMA_RTC:
689 case INT_TYPE_AI3_DMA_RTC:
690 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
691 mod_timer(&devpriv->rtc_irq_timer,
692 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
694 for (i = 0; i < 10; i++) {
695 top1 = get_dma_residue(devpriv->dma);
696 top2 = get_dma_residue(devpriv->dma);
703 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
705 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
707 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
709 return IRQ_HANDLED; /* exit=no new samples from last call */
711 i = devpriv->last_top_dma - 1;
712 i &= (devpriv->dmasamplsize - 1);
714 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
715 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
716 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
717 pcl818_ai_cancel(dev, s);
718 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
719 comedi_event(dev, s);
722 /* printk("r %ld ",ofs_dats); */
724 bufptr = devpriv->last_top_dma;
726 for (i = 0; i < ofs_dats; i++) {
727 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
729 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
730 (dmabuf[bufptr] & 0xf),
732 act_chanlist[devpriv->act_chanlist_pos]);
733 pcl818_ai_cancel(dev, s);
735 COMEDI_CB_EOA | COMEDI_CB_ERROR;
736 comedi_event(dev, s);
740 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
741 bufptr &= (devpriv->dmasamplsize - 1);
743 devpriv->act_chanlist_pos++;
744 if (devpriv->act_chanlist_pos >=
745 devpriv->act_chanlist_len) {
746 devpriv->act_chanlist_pos = 0;
748 s->async->cur_chan++;
749 if (s->async->cur_chan >= devpriv->ai_n_chan) {
750 s->async->cur_chan = 0;
751 devpriv->ai_act_scan--;
754 if (!devpriv->neverending_ai)
755 if (devpriv->ai_act_scan == 0) { /* all data sampled */
756 pcl818_ai_cancel(dev, s);
757 s->async->events |= COMEDI_CB_EOA;
758 comedi_event(dev, s);
759 /* printk("done int ai13 dma\n"); */
764 devpriv->last_top_dma = bufptr;
766 bufptr &= (devpriv->dmasamplsize - 1);
767 dmabuf[bufptr] = MAGIC_DMA_WORD;
768 comedi_event(dev, s);
779 ==============================================================================
780 analog input interrupt mode 1 & 3, 818HD/HG cards
782 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
784 struct comedi_device *dev = d;
785 struct comedi_subdevice *s = dev->subdevices + 0;
788 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
790 lo = inb(dev->iobase + PCL818_FI_STATUS);
793 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
794 pcl818_ai_cancel(dev, s);
795 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
796 comedi_event(dev, s);
801 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
802 pcl818_ai_cancel(dev, s);
803 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
804 comedi_event(dev, s);
814 for (i = 0; i < len; i++) {
815 lo = inb(dev->iobase + PCL818_FI_DATALO);
816 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
818 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
820 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
821 pcl818_ai_cancel(dev, s);
822 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
823 comedi_event(dev, s);
827 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
829 devpriv->act_chanlist_pos++;
830 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
831 devpriv->act_chanlist_pos = 0;
833 s->async->cur_chan++;
834 if (s->async->cur_chan >= devpriv->ai_n_chan) {
835 s->async->cur_chan = 0;
836 devpriv->ai_act_scan--;
839 if (!devpriv->neverending_ai)
840 if (devpriv->ai_act_scan == 0) { /* all data sampled */
841 pcl818_ai_cancel(dev, s);
842 s->async->events |= COMEDI_CB_EOA;
843 comedi_event(dev, s);
849 comedi_event(dev, s);
854 ==============================================================================
857 static irqreturn_t interrupt_pcl818(int irq, void *d)
859 struct comedi_device *dev = d;
861 if (!dev->attached) {
862 comedi_error(dev, "premature interrupt");
867 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
868 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
869 devpriv->ai_act_scan > 0)) &&
870 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
871 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
872 /* The cleanup from ai_cancel() has been delayed
873 until now because the card doesn't seem to like
874 being reprogrammed while a DMA transfer is in
877 struct comedi_subdevice *s = dev->subdevices + 0;
878 devpriv->ai_act_scan = 0;
879 devpriv->neverending_ai = 0;
880 pcl818_ai_cancel(dev, s);
883 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
888 switch (devpriv->ai_mode) {
889 case INT_TYPE_AI1_DMA:
890 case INT_TYPE_AI3_DMA:
891 return interrupt_pcl818_ai_mode13_dma(irq, d);
892 case INT_TYPE_AI1_INT:
893 case INT_TYPE_AI3_INT:
894 return interrupt_pcl818_ai_mode13_int(irq, d);
895 case INT_TYPE_AI1_FIFO:
896 case INT_TYPE_AI3_FIFO:
897 return interrupt_pcl818_ai_mode13_fifo(irq, d);
898 #ifdef PCL818_MODE13_AO
899 case INT_TYPE_AO1_INT:
900 case INT_TYPE_AO3_INT:
901 return interrupt_pcl818_ao_mode13_int(irq, d);
907 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
909 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
910 || (!devpriv->ai_mode)) {
911 comedi_error(dev, "bad IRQ!");
915 comedi_error(dev, "IRQ from unknown source!");
920 ==============================================================================
921 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
923 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
924 struct comedi_subdevice *s)
929 printk("mode13dma_int, mode: %d\n", mode);
930 disable_dma(devpriv->dma); /* disable dma */
931 bytes = devpriv->hwdmasize[0];
932 if (!devpriv->neverending_ai) {
933 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
934 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
935 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
936 devpriv->dma_runs_to_end--;
937 if (devpriv->dma_runs_to_end >= 0)
938 bytes = devpriv->hwdmasize[0];
941 devpriv->next_dma_buf = 0;
942 set_dma_mode(devpriv->dma, DMA_MODE_READ);
943 flags = claim_dma_lock();
944 clear_dma_ff(devpriv->dma);
945 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
946 set_dma_count(devpriv->dma, bytes);
947 release_dma_lock(flags);
948 enable_dma(devpriv->dma);
951 devpriv->ai_mode = INT_TYPE_AI1_DMA;
952 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
954 devpriv->ai_mode = INT_TYPE_AI3_DMA;
955 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
961 ==============================================================================
962 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
964 static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
965 struct comedi_subdevice *s)
970 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
971 flags = claim_dma_lock();
972 clear_dma_ff(devpriv->dma);
973 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
974 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
975 release_dma_lock(flags);
976 enable_dma(devpriv->dma);
977 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
978 pole = (short *)devpriv->dmabuf[0];
979 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
980 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
982 devpriv->rtc_freq = rtc_setfreq_irq(2048);
983 devpriv->rtc_irq_timer.expires =
984 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
985 devpriv->rtc_irq_timer.data = (unsigned long)dev;
986 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
988 add_timer(&devpriv->rtc_irq_timer);
992 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
993 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
995 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
996 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
1002 ==============================================================================
1003 ANALOG INPUT MODE 1 or 3, 818 cards
1005 static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
1006 struct comedi_subdevice *s)
1008 struct comedi_cmd *cmd = &s->async->cmd;
1009 int divisor1 = 0, divisor2 = 0;
1010 unsigned int seglen;
1012 printk("pcl818_ai_cmd_mode()\n");
1013 if ((!dev->irq) && (!devpriv->dma_rtc)) {
1014 comedi_error(dev, "IRQ not defined!");
1018 if (devpriv->irq_blocked)
1021 start_pacer(dev, -1, 0, 0); /* stop pacer */
1023 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
1024 devpriv->ai_n_chan);
1027 setup_channel_list(dev, s, devpriv->ai_chanlist,
1028 devpriv->ai_n_chan, seglen);
1032 devpriv->ai_act_scan = devpriv->ai_scans;
1033 devpriv->ai_act_chan = 0;
1034 devpriv->irq_blocked = 1;
1035 devpriv->irq_was_now_closed = 0;
1036 devpriv->neverending_ai = 0;
1037 devpriv->act_chanlist_pos = 0;
1038 devpriv->dma_runs_to_end = 0;
1040 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
1041 devpriv->neverending_ai = 1; /* well, user want neverending */
1044 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1045 &divisor2, &cmd->convert_arg,
1046 TRIG_ROUND_NEAREST);
1047 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
1051 if (divisor2 == 1) {
1057 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1059 switch (devpriv->dma) {
1062 if (devpriv->dma_rtc == 0) {
1063 pcl818_ai_mode13dma_int(mode, dev, s);
1067 pcl818_ai_mode13dma_rtc(mode, dev, s);
1076 if (!devpriv->usefifo) {
1078 /* printk("IRQ\n"); */
1080 devpriv->ai_mode = INT_TYPE_AI1_INT;
1082 outb(0x83 | (dev->irq << 4),
1083 dev->iobase + PCL818_CONTROL);
1085 devpriv->ai_mode = INT_TYPE_AI3_INT;
1087 outb(0x82 | (dev->irq << 4),
1088 dev->iobase + PCL818_CONTROL);
1093 outb(1, dev->iobase + PCL818_FI_ENABLE);
1095 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1097 outb(0x03, dev->iobase + PCL818_CONTROL);
1099 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1100 outb(0x02, dev->iobase + PCL818_CONTROL);
1105 start_pacer(dev, mode, divisor1, divisor2);
1108 switch (devpriv->ai_mode) {
1109 case INT_TYPE_AI1_DMA_RTC:
1110 case INT_TYPE_AI3_DMA_RTC:
1111 set_rtc_irq_bit(1); /* start RTC */
1115 printk("pcl818_ai_cmd_mode() end\n");
1121 ==============================================================================
1122 ANALOG OUTPUT MODE 1 or 3, 818 cards
1124 #ifdef PCL818_MODE13_AO
1125 static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1126 struct comedi_subdevice *s, comedi_trig * it)
1128 int divisor1 = 0, divisor2 = 0;
1131 comedi_error(dev, "IRQ not defined!");
1135 if (devpriv->irq_blocked)
1138 start_pacer(dev, -1, 0, 0); /* stop pacer */
1140 devpriv->int13_act_scan = it->n;
1141 devpriv->int13_act_chan = 0;
1142 devpriv->irq_blocked = 1;
1143 devpriv->irq_was_now_closed = 0;
1144 devpriv->neverending_ai = 0;
1145 devpriv->act_chanlist_pos = 0;
1148 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1149 &divisor2, &it->trigvar,
1150 TRIG_ROUND_NEAREST);
1151 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1155 if (divisor2 == 1) {
1161 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1163 devpriv->int818_mode = INT_TYPE_AO1_INT;
1164 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1166 devpriv->int818_mode = INT_TYPE_AO3_INT;
1167 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1170 start_pacer(dev, mode, divisor1, divisor2);
1176 ==============================================================================
1177 ANALOG OUTPUT MODE 1, 818 cards
1179 static int pcl818_ao_mode1(struct comedi_device *dev,
1180 struct comedi_subdevice *s, comedi_trig * it)
1182 return pcl818_ao_mode13(1, dev, s, it);
1186 ==============================================================================
1187 ANALOG OUTPUT MODE 3, 818 cards
1189 static int pcl818_ao_mode3(struct comedi_device *dev,
1190 struct comedi_subdevice *s, comedi_trig * it)
1192 return pcl818_ao_mode13(3, dev, s, it);
1198 ==============================================================================
1199 Start/stop pacer onboard pacer
1201 static void start_pacer(struct comedi_device *dev, int mode,
1202 unsigned int divisor1, unsigned int divisor2)
1204 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1205 outb(0x74, dev->iobase + PCL818_CTRCTL);
1209 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1210 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1211 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1212 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1217 ==============================================================================
1218 Check if channel list from user is builded correctly
1219 If it's ok, then program scan/gain logic
1221 static int check_channel_list(struct comedi_device *dev,
1222 struct comedi_subdevice *s,
1223 unsigned int *chanlist, unsigned int n_chan)
1225 unsigned int chansegment[16];
1226 unsigned int i, nowmustbechan, seglen, segpos;
1228 /* correct channel and range number check itself comedi/range.c */
1230 comedi_error(dev, "range/channel list is empty!");
1235 /* first channel is every time ok */
1236 chansegment[0] = chanlist[0];
1237 /* build part of chanlist */
1238 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1240 /* printk("%d. %d * %d\n",i,
1241 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1243 /* we detect loop, this must by finish */
1245 if (chanlist[0] == chanlist[i])
1248 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1249 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
1251 ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
1252 dev->minor, i, CR_CHAN(chanlist[i]),
1253 nowmustbechan, CR_CHAN(chanlist[0]));
1256 /* well, this is next correct channel in list */
1257 chansegment[i] = chanlist[i];
1260 /* check whole chanlist */
1261 for (i = 0, segpos = 0; i < n_chan; i++) {
1262 /* 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])); */
1263 if (chanlist[i] != chansegment[i % seglen]) {
1265 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1266 dev->minor, i, CR_CHAN(chansegment[i]),
1267 CR_RANGE(chansegment[i]),
1268 CR_AREF(chansegment[i]),
1269 CR_CHAN(chanlist[i % seglen]),
1270 CR_RANGE(chanlist[i % seglen]),
1271 CR_AREF(chansegment[i % seglen]));
1272 return 0; /* chan/gain list is strange */
1278 printk("check_channel_list: seglen %d\n", seglen);
1282 static void setup_channel_list(struct comedi_device *dev,
1283 struct comedi_subdevice *s,
1284 unsigned int *chanlist, unsigned int n_chan,
1285 unsigned int seglen)
1289 devpriv->act_chanlist_len = seglen;
1290 devpriv->act_chanlist_pos = 0;
1292 for (i = 0; i < seglen; i++) { /* store range list to card */
1293 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1294 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1295 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1300 /* select channel interval to scan */
1301 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1303 dev->iobase + PCL818_MUX);
1307 ==============================================================================
1308 Check if board is switched to SE (1) or DIFF(0) mode
1310 static int check_single_ended(unsigned int port)
1312 if (inb(port + PCL818_STATUS) & 0x20) {
1320 ==============================================================================
1322 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1323 struct comedi_cmd *cmd)
1326 int tmp, divisor1 = 0, divisor2 = 0;
1328 /* step 1: make sure trigger sources are trivially valid */
1330 tmp = cmd->start_src;
1331 cmd->start_src &= TRIG_NOW;
1332 if (!cmd->start_src || tmp != cmd->start_src)
1335 tmp = cmd->scan_begin_src;
1336 cmd->scan_begin_src &= TRIG_FOLLOW;
1337 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1340 tmp = cmd->convert_src;
1341 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1342 if (!cmd->convert_src || tmp != cmd->convert_src)
1345 tmp = cmd->scan_end_src;
1346 cmd->scan_end_src &= TRIG_COUNT;
1347 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1350 tmp = cmd->stop_src;
1351 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1352 if (!cmd->stop_src || tmp != cmd->stop_src)
1359 /* step 2: make sure trigger sources are unique and mutually compatible */
1361 if (cmd->start_src != TRIG_NOW) {
1362 cmd->start_src = TRIG_NOW;
1365 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1366 cmd->scan_begin_src = TRIG_FOLLOW;
1369 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1372 if (cmd->scan_end_src != TRIG_COUNT) {
1373 cmd->scan_end_src = TRIG_COUNT;
1377 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1384 /* step 3: make sure arguments are trivially compatible */
1386 if (cmd->start_arg != 0) {
1391 if (cmd->scan_begin_arg != 0) {
1392 cmd->scan_begin_arg = 0;
1396 if (cmd->convert_src == TRIG_TIMER) {
1397 if (cmd->convert_arg < this_board->ns_min) {
1398 cmd->convert_arg = this_board->ns_min;
1401 } else { /* TRIG_EXT */
1402 if (cmd->convert_arg != 0) {
1403 cmd->convert_arg = 0;
1408 if (cmd->scan_end_arg != cmd->chanlist_len) {
1409 cmd->scan_end_arg = cmd->chanlist_len;
1412 if (cmd->stop_src == TRIG_COUNT) {
1413 if (!cmd->stop_arg) {
1417 } else { /* TRIG_NONE */
1418 if (cmd->stop_arg != 0) {
1428 /* step 4: fix up any arguments */
1430 if (cmd->convert_src == TRIG_TIMER) {
1431 tmp = cmd->convert_arg;
1432 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1433 &divisor2, &cmd->convert_arg,
1434 cmd->flags & TRIG_ROUND_MASK);
1435 if (cmd->convert_arg < this_board->ns_min)
1436 cmd->convert_arg = this_board->ns_min;
1437 if (tmp != cmd->convert_arg)
1445 /* step 5: complain about special chanlist considerations */
1447 if (cmd->chanlist) {
1448 if (!check_channel_list(dev, s, cmd->chanlist,
1450 return 5; /* incorrect channels list */
1457 ==============================================================================
1459 static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1461 struct comedi_cmd *cmd = &s->async->cmd;
1464 printk("pcl818_ai_cmd()\n");
1465 devpriv->ai_n_chan = cmd->chanlist_len;
1466 devpriv->ai_chanlist = cmd->chanlist;
1467 devpriv->ai_flags = cmd->flags;
1468 devpriv->ai_data_len = s->async->prealloc_bufsz;
1469 devpriv->ai_data = s->async->prealloc_buf;
1470 devpriv->ai_timer1 = 0;
1471 devpriv->ai_timer2 = 0;
1473 if (cmd->stop_src == TRIG_COUNT) {
1474 devpriv->ai_scans = cmd->stop_arg;
1476 devpriv->ai_scans = 0;
1479 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1480 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
1481 devpriv->ai_timer1 = cmd->convert_arg;
1482 retval = pcl818_ai_cmd_mode(1, dev, s);
1483 printk("pcl818_ai_cmd() end\n");
1486 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1487 return pcl818_ai_cmd_mode(3, dev, s);
1495 ==============================================================================
1496 cancel any mode 1-4 AI
1498 static int pcl818_ai_cancel(struct comedi_device *dev,
1499 struct comedi_subdevice *s)
1501 if (devpriv->irq_blocked > 0) {
1502 printk("pcl818_ai_cancel()\n");
1503 devpriv->irq_was_now_closed = 1;
1505 switch (devpriv->ai_mode) {
1507 case INT_TYPE_AI1_DMA_RTC:
1508 case INT_TYPE_AI3_DMA_RTC:
1509 set_rtc_irq_bit(0); /* stop RTC */
1510 del_timer(&devpriv->rtc_irq_timer);
1512 case INT_TYPE_AI1_DMA:
1513 case INT_TYPE_AI3_DMA:
1514 if (devpriv->neverending_ai ||
1515 (!devpriv->neverending_ai &&
1516 devpriv->ai_act_scan > 0)) {
1517 /* wait for running dma transfer to end, do cleanup in interrupt */
1520 disable_dma(devpriv->dma);
1521 case INT_TYPE_AI1_INT:
1522 case INT_TYPE_AI3_INT:
1523 case INT_TYPE_AI1_FIFO:
1524 case INT_TYPE_AI3_FIFO:
1525 #ifdef PCL818_MODE13_AO
1526 case INT_TYPE_AO1_INT:
1527 case INT_TYPE_AO3_INT:
1529 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1531 start_pacer(dev, -1, 0, 0);
1532 outb(0, dev->iobase + PCL818_AD_LO);
1533 inb(dev->iobase + PCL818_AD_LO);
1534 inb(dev->iobase + PCL818_AD_HI);
1535 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1536 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1537 if (devpriv->usefifo) { /* FIFO shutdown */
1538 outb(0, dev->iobase + PCL818_FI_INTCLR);
1539 outb(0, dev->iobase + PCL818_FI_FLUSH);
1540 outb(0, dev->iobase + PCL818_FI_ENABLE);
1542 devpriv->irq_blocked = 0;
1543 devpriv->last_int_sub = s;
1544 devpriv->neverending_ai = 0;
1545 devpriv->ai_mode = 0;
1546 devpriv->irq_was_now_closed = 0;
1552 printk("pcl818_ai_cancel() end\n");
1557 ==============================================================================
1560 static int pcl818_check(unsigned long iobase)
1562 outb(0x00, iobase + PCL818_MUX);
1564 if (inb(iobase + PCL818_MUX) != 0x00)
1565 return 1; /* there isn't card */
1566 outb(0x55, iobase + PCL818_MUX);
1568 if (inb(iobase + PCL818_MUX) != 0x55)
1569 return 1; /* there isn't card */
1570 outb(0x00, iobase + PCL818_MUX);
1572 outb(0x18, iobase + PCL818_CONTROL);
1574 if (inb(iobase + PCL818_CONTROL) != 0x18)
1575 return 1; /* there isn't card */
1576 return 0; /* ok, card exist */
1580 ==============================================================================
1581 reset whole PCL-818 cards
1583 static void pcl818_reset(struct comedi_device *dev)
1585 if (devpriv->usefifo) { /* FIFO shutdown */
1586 outb(0, dev->iobase + PCL818_FI_INTCLR);
1587 outb(0, dev->iobase + PCL818_FI_FLUSH);
1588 outb(0, dev->iobase + PCL818_FI_ENABLE);
1590 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
1591 outb(0, dev->iobase + PCL818_DA_HI);
1593 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
1594 outb(0, dev->iobase + PCL818_DO_LO);
1596 outb(0, dev->iobase + PCL818_CONTROL);
1597 outb(0, dev->iobase + PCL818_CNTENABLE);
1598 outb(0, dev->iobase + PCL818_MUX);
1599 outb(0, dev->iobase + PCL818_CLRINT);
1600 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1601 outb(0x70, dev->iobase + PCL818_CTRCTL);
1602 outb(0x30, dev->iobase + PCL818_CTRCTL);
1603 if (this_board->is_818) {
1604 outb(0, dev->iobase + PCL818_RANGE);
1606 outb(0, dev->iobase + PCL718_DA2_LO);
1607 outb(0, dev->iobase + PCL718_DA2_HI);
1613 ==============================================================================
1614 Enable(1)/disable(0) periodic interrupts from RTC
1616 static int set_rtc_irq_bit(unsigned char bit)
1619 unsigned long flags;
1623 if (RTC_timer_lock > 1)
1627 if (RTC_timer_lock < 0)
1629 if (RTC_timer_lock > 0)
1635 val = CMOS_READ(RTC_CONTROL);
1641 CMOS_WRITE(val, RTC_CONTROL);
1642 CMOS_READ(RTC_INTR_FLAGS);
1643 restore_flags(flags);
1648 ==============================================================================
1649 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1651 static void rtc_dropped_irq(unsigned long data)
1653 struct comedi_device *dev = (void *)data;
1654 unsigned long flags, tmp;
1656 switch (devpriv->int818_mode) {
1657 case INT_TYPE_AI1_DMA_RTC:
1658 case INT_TYPE_AI3_DMA_RTC:
1659 mod_timer(&devpriv->rtc_irq_timer,
1660 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1663 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1664 restore_flags(flags);
1670 ==============================================================================
1671 Set frequency of interrupts from RTC
1673 static int rtc_setfreq_irq(int freq)
1678 unsigned long flags;
1685 while (freq > (1 << tmp))
1688 rtc_freq = 1 << tmp;
1692 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1694 CMOS_WRITE(val, RTC_FREQ_SELECT);
1695 restore_flags(flags);
1701 ==============================================================================
1702 Free any resources that we have claimed
1704 static void free_resources(struct comedi_device *dev)
1706 /* printk("free_resource()\n"); */
1708 pcl818_ai_cancel(dev, devpriv->sub_ai);
1711 free_dma(devpriv->dma);
1712 if (devpriv->dmabuf[0])
1713 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1714 if (devpriv->dmabuf[1])
1715 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1717 if (devpriv->rtc_irq)
1718 free_irq(devpriv->rtc_irq, dev);
1719 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1720 if (devpriv->rtc_iobase)
1721 release_region(devpriv->rtc_iobase,
1722 devpriv->rtc_iosize);
1724 if (devpriv->dma_rtc)
1730 free_irq(dev->irq, dev);
1732 release_region(dev->iobase, devpriv->io_range);
1733 /* printk("free_resource() end\n"); */
1737 ==============================================================================
1742 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1745 unsigned long iobase;
1748 unsigned long pages;
1749 struct comedi_subdevice *s;
1751 ret = alloc_private(dev, sizeof(struct pcl818_private));
1753 return ret; /* Can't alloc mem */
1755 /* claim our I/O space */
1756 iobase = it->options[0];
1757 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1758 dev->minor, this_board->name, iobase);
1759 devpriv->io_range = this_board->io_range;
1760 if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */
1761 devpriv->io_range = PCLx1xFIFO_RANGE;
1762 devpriv->usefifo = 1;
1764 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1765 printk("I/O port conflict\n");
1769 dev->iobase = iobase;
1771 if (pcl818_check(iobase)) {
1772 printk(", I can't detect board. FAIL!\n");
1776 /* set up some name stuff */
1777 dev->board_name = this_board->name;
1780 if (this_board->IRQbits != 0) { /* board support IRQ */
1781 irq = it->options[1];
1782 if (irq) { /* we want to use IRQ */
1783 if (((1 << irq) & this_board->IRQbits) == 0) {
1785 (", IRQ %u is out of allowed range, DISABLING IT",
1787 irq = 0; /* Bad IRQ */
1790 (irq, interrupt_pcl818, 0, "pcl818", dev)) {
1792 (", unable to allocate IRQ %u, DISABLING IT",
1794 irq = 0; /* Can't use IRQ */
1796 printk(", irq=%u", irq);
1804 devpriv->irq_free = 1;
1805 } /* 1=we have allocated irq */
1807 devpriv->irq_free = 0;
1809 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1810 devpriv->ai_mode = 0; /* mode of irq */
1813 /* grab RTC for DMA operations */
1814 devpriv->dma_rtc = 0;
1815 if (it->options[2] > 0) { /* we want to use DMA */
1816 if (RTC_lock == 0) {
1817 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1821 devpriv->rtc_iobase = RTC_PORT(0);
1822 devpriv->rtc_iosize = RTC_IO_EXTENT;
1824 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
1825 "pcl818 DMA (RTC)", dev)) {
1826 devpriv->dma_rtc = 1;
1827 devpriv->rtc_irq = RTC_IRQ;
1828 printk(", dma_irq=%u", devpriv->rtc_irq);
1831 if (RTC_lock == 0) {
1832 if (devpriv->rtc_iobase)
1833 release_region(devpriv->rtc_iobase,
1834 devpriv->rtc_iosize);
1836 devpriv->rtc_iobase = 0;
1837 devpriv->rtc_iosize = 0;
1846 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1847 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1848 if (this_board->DMAbits != 0) { /* board support DMA */
1849 dma = it->options[2];
1851 goto no_dma; /* DMA disabled */
1852 if (((1 << dma) & this_board->DMAbits) == 0) {
1853 printk(", DMA is out of allowed range, FAIL!\n");
1854 return -EINVAL; /* Bad DMA */
1856 ret = request_dma(dma, "pcl818");
1858 printk(", unable to allocate DMA %u, FAIL!\n", dma);
1859 return -EBUSY; /* DMA isn't free */
1862 printk(", dma=%u", dma);
1863 pages = 2; /* we need 16KB */
1864 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1865 if (!devpriv->dmabuf[0]) {
1866 printk(", unable to allocate DMA buffer, FAIL!\n");
1867 /* maybe experiment with try_to_free_pages() will help .... */
1868 return -EBUSY; /* no buffer :-( */
1870 devpriv->dmapages[0] = pages;
1871 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1872 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1873 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1874 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1875 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1876 if (!devpriv->dmabuf[1]) {
1878 (", unable to allocate DMA buffer, FAIL!\n");
1881 devpriv->dmapages[1] = pages;
1882 devpriv->hwdmaptr[1] =
1883 virt_to_bus((void *)devpriv->dmabuf[1]);
1884 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1890 ret = alloc_subdevices(dev, 4);
1894 s = dev->subdevices + 0;
1895 if (!this_board->n_aichan_se) {
1896 s->type = COMEDI_SUBD_UNUSED;
1898 s->type = COMEDI_SUBD_AI;
1899 devpriv->sub_ai = s;
1900 s->subdev_flags = SDF_READABLE;
1901 if (check_single_ended(dev->iobase)) {
1902 s->n_chan = this_board->n_aichan_se;
1903 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1904 printk(", %dchans S.E. DAC", s->n_chan);
1906 s->n_chan = this_board->n_aichan_diff;
1907 s->subdev_flags |= SDF_DIFF;
1908 printk(", %dchans DIFF DAC", s->n_chan);
1910 s->maxdata = this_board->ai_maxdata;
1911 s->len_chanlist = s->n_chan;
1912 s->range_table = this_board->ai_range_type;
1913 s->cancel = pcl818_ai_cancel;
1914 s->insn_read = pcl818_ai_insn_read;
1915 if ((irq) || (devpriv->dma_rtc)) {
1916 dev->read_subdev = s;
1917 s->subdev_flags |= SDF_CMD_READ;
1918 s->do_cmdtest = ai_cmdtest;
1921 if (this_board->is_818) {
1922 if ((it->options[4] == 1) || (it->options[4] == 10))
1923 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
1925 switch (it->options[4]) {
1927 s->range_table = &range_bipolar10;
1930 s->range_table = &range_bipolar5;
1933 s->range_table = &range_bipolar2_5;
1936 s->range_table = &range718_bipolar1;
1939 s->range_table = &range718_bipolar0_5;
1942 s->range_table = &range_unipolar10;
1945 s->range_table = &range_unipolar5;
1948 s->range_table = &range718_unipolar2;
1951 s->range_table = &range718_unipolar1;
1954 s->range_table = &range_unknown;
1960 s = dev->subdevices + 1;
1961 if (!this_board->n_aochan) {
1962 s->type = COMEDI_SUBD_UNUSED;
1964 s->type = COMEDI_SUBD_AO;
1965 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1966 s->n_chan = this_board->n_aochan;
1967 s->maxdata = this_board->ao_maxdata;
1968 s->len_chanlist = this_board->n_aochan;
1969 s->range_table = this_board->ao_range_type;
1970 s->insn_read = pcl818_ao_insn_read;
1971 s->insn_write = pcl818_ao_insn_write;
1973 #ifdef PCL818_MODE13_AO
1975 s->trig[1] = pcl818_ao_mode1;
1976 s->trig[3] = pcl818_ao_mode3;
1980 if (this_board->is_818) {
1981 if ((it->options[4] == 1) || (it->options[4] == 10))
1982 s->range_table = &range_unipolar10;
1983 if (it->options[4] == 2)
1984 s->range_table = &range_unknown;
1986 if ((it->options[5] == 1) || (it->options[5] == 10))
1987 s->range_table = &range_unipolar10;
1988 if (it->options[5] == 2)
1989 s->range_table = &range_unknown;
1993 s = dev->subdevices + 2;
1994 if (!this_board->n_dichan) {
1995 s->type = COMEDI_SUBD_UNUSED;
1997 s->type = COMEDI_SUBD_DI;
1998 s->subdev_flags = SDF_READABLE;
1999 s->n_chan = this_board->n_dichan;
2001 s->len_chanlist = this_board->n_dichan;
2002 s->range_table = &range_digital;
2003 s->insn_bits = pcl818_di_insn_bits;
2006 s = dev->subdevices + 3;
2007 if (!this_board->n_dochan) {
2008 s->type = COMEDI_SUBD_UNUSED;
2010 s->type = COMEDI_SUBD_DO;
2011 s->subdev_flags = SDF_WRITABLE;
2012 s->n_chan = this_board->n_dochan;
2014 s->len_chanlist = this_board->n_dochan;
2015 s->range_table = &range_digital;
2016 s->insn_bits = pcl818_do_insn_bits;
2019 /* select 1/10MHz oscilator */
2020 if ((it->options[3] == 0) || (it->options[3] == 10)) {
2021 devpriv->i8253_osc_base = 100;
2023 devpriv->i8253_osc_base = 1000;
2026 /* max sampling speed */
2027 devpriv->ns_min = this_board->ns_min;
2029 if (!this_board->is_818) {
2030 if ((it->options[6] == 1) || (it->options[6] == 100))
2031 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
2042 ==============================================================================
2045 static int pcl818_detach(struct comedi_device *dev)
2047 /* printk("comedi%d: pcl818: remove\n", dev->minor); */
2048 free_resources(dev);
2052 MODULE_AUTHOR("Comedi http://www.comedi.org");
2053 MODULE_DESCRIPTION("Comedi low-level driver");
2054 MODULE_LICENSE("GPL");