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>
111 /* #define PCL818_MODE13_AO 1 */
113 /* boards constants */
115 #define boardPCL818L 0
116 #define boardPCL818H 1
117 #define boardPCL818HD 2
118 #define boardPCL818HG 3
119 #define boardPCL818 4
120 #define boardPCL718 5
123 #define PCLx1x_RANGE 16
124 /* IO space len if we use FIFO */
125 #define PCLx1xFIFO_RANGE 32
127 /* W: clear INT request */
128 #define PCL818_CLRINT 8
129 /* R: return status byte */
130 #define PCL818_STATUS 8
131 /* R: A/D high byte W: A/D range control */
132 #define PCL818_RANGE 1
133 /* R: next mux scan channel W: mux scan channel & range control pointer */
135 /* R/W: operation control register */
136 #define PCL818_CONTROL 9
137 /* W: counter enable */
138 #define PCL818_CNTENABLE 10
140 /* R: low byte of A/D W: soft A/D trigger */
141 #define PCL818_AD_LO 0
142 /* R: high byte of A/D W: A/D range control */
143 #define PCL818_AD_HI 1
144 /* W: D/A low&high byte */
145 #define PCL818_DA_LO 4
146 #define PCL818_DA_HI 5
147 /* R: low&high byte of DI */
148 #define PCL818_DI_LO 3
149 #define PCL818_DI_HI 11
150 /* W: low&high byte of DO */
151 #define PCL818_DO_LO 3
152 #define PCL818_DO_HI 11
153 /* W: PCL718 second D/A */
154 #define PCL718_DA2_LO 6
155 #define PCL718_DA2_HI 7
157 #define PCL818_CTR0 12
158 #define PCL818_CTR1 13
159 #define PCL818_CTR2 14
160 /* W: counter control */
161 #define PCL818_CTRCTL 15
163 /* W: fifo enable/disable */
164 #define PCL818_FI_ENABLE 6
165 /* W: fifo interrupt clear */
166 #define PCL818_FI_INTCLR 20
167 /* W: fifo interrupt clear */
168 #define PCL818_FI_FLUSH 25
170 #define PCL818_FI_STATUS 25
171 /* R: one record from FIFO */
172 #define PCL818_FI_DATALO 23
173 #define PCL818_FI_DATAHI 23
175 /* type of interrupt handler */
176 #define INT_TYPE_AI1_INT 1
177 #define INT_TYPE_AI1_DMA 2
178 #define INT_TYPE_AI1_FIFO 3
179 #define INT_TYPE_AI3_INT 4
180 #define INT_TYPE_AI3_DMA 5
181 #define INT_TYPE_AI3_FIFO 6
182 #ifdef PCL818_MODE13_AO
183 #define INT_TYPE_AO1_INT 7
184 #define INT_TYPE_AO3_INT 8
189 #define INT_TYPE_AI1_DMA_RTC 9
190 #define INT_TYPE_AI3_DMA_RTC 10
193 #define RTC_IO_EXTENT 0x10
196 #define MAGIC_DMA_WORD 0x5a5a
198 static const struct comedi_lrange range_pcl818h_ai = { 9, {
211 static const struct comedi_lrange range_pcl818hg_ai = { 10, {
227 static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
235 static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
243 static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
244 static const struct comedi_lrange range718_bipolar0_5 =
245 { 1, {BIP_RANGE(0.5),} };
246 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
247 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
249 static int pcl818_attach(struct comedi_device *dev,
250 struct comedi_devconfig *it);
251 static int pcl818_detach(struct comedi_device *dev);
254 static int RTC_lock = 0; /* RTC lock */
255 static int RTC_timer_lock = 0; /* RTC int lock */
258 struct pcl818_board {
260 const char *name; /* driver name */
261 int n_ranges; /* len of range list */
262 int n_aichan_se; /* num of A/D chans in single ended mode */
263 int n_aichan_diff; /* num of A/D chans in diferencial mode */
264 unsigned int ns_min; /* minimal alllowed delay between samples (in ns) */
265 int n_aochan; /* num of D/A chans */
266 int n_dichan; /* num of DI chans */
267 int n_dochan; /* num of DO chans */
268 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
269 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
270 unsigned int io_range; /* len of IO space */
271 unsigned int IRQbits; /* allowed interrupts */
272 unsigned int DMAbits; /* allowed DMA chans */
273 int ai_maxdata; /* maxdata for A/D */
274 int ao_maxdata; /* maxdata for D/A */
275 unsigned char fifo; /* 1=board has FIFO */
279 static const struct pcl818_board boardtypes[] = {
280 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
281 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
282 0x0a, 0xfff, 0xfff, 0, 1},
283 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
284 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
285 0x0a, 0xfff, 0xfff, 0, 1},
286 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
287 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
288 0x0a, 0xfff, 0xfff, 1, 1},
289 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
290 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
291 0x0a, 0xfff, 0xfff, 1, 1},
292 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
293 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
294 0x0a, 0xfff, 0xfff, 0, 1},
295 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
296 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
297 0x0a, 0xfff, 0xfff, 0, 0},
299 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
300 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
301 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
304 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
306 static struct comedi_driver driver_pcl818 = {
307 .driver_name = "pcl818",
308 .module = THIS_MODULE,
309 .attach = pcl818_attach,
310 .detach = pcl818_detach,
311 .board_name = &boardtypes[0].name,
312 .num_names = n_boardtypes,
313 .offset = sizeof(struct pcl818_board),
316 static int __init driver_pcl818_init_module(void)
318 return comedi_driver_register(&driver_pcl818);
321 static void __exit driver_pcl818_cleanup_module(void)
323 comedi_driver_unregister(&driver_pcl818);
326 module_init(driver_pcl818_init_module);
327 module_exit(driver_pcl818_cleanup_module);
329 struct pcl818_private {
331 unsigned int dma; /* used DMA, 0=don't use DMA */
332 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
333 unsigned int io_range;
335 unsigned long rtc_iobase; /* RTC port region */
336 unsigned int rtc_iosize;
337 unsigned int rtc_irq;
338 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
339 unsigned long rtc_freq; /* RTC int freq */
340 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
342 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
343 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
344 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
345 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
346 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
347 unsigned int last_top_dma; /* DMA pointer in last RTC int */
348 int next_dma_buf; /* which DMA buffer will be used next round */
349 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
350 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
351 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
352 unsigned int ns_min; /* manimal alllowed delay between samples (in us) for actual card */
353 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
354 int irq_free; /* 1=have allocated IRQ */
355 int irq_blocked; /* 1=IRQ now uses any subdev */
356 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
357 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
358 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
359 int ai_act_scan; /* how many scans we finished */
360 int ai_act_chan; /* actual position in actual scan */
361 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
362 unsigned int act_chanlist_len; /* how long is actual MUX list */
363 unsigned int act_chanlist_pos; /* actual position in MUX list */
364 unsigned int ai_scans; /* len of scanlist */
365 unsigned int ai_n_chan; /* how many channels is measured */
366 unsigned int *ai_chanlist; /* actaul chanlist */
367 unsigned int ai_flags; /* flaglist */
368 unsigned int ai_data_len; /* len of data buffer */
369 short *ai_data; /* data buffer */
370 unsigned int ai_timer1; /* timers */
371 unsigned int ai_timer2;
372 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
373 unsigned char usefifo; /* 1=use fifo */
374 unsigned int ao_readback[2];
377 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
378 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
381 #define devpriv ((struct pcl818_private *)dev->private)
382 #define this_board ((const struct pcl818_board *)dev->board_ptr)
385 ==============================================================================
387 static void setup_channel_list(struct comedi_device *dev,
388 struct comedi_subdevice *s,
389 unsigned int *chanlist, unsigned int n_chan,
390 unsigned int seglen);
391 static int check_channel_list(struct comedi_device *dev,
392 struct comedi_subdevice *s,
393 unsigned int *chanlist, unsigned int n_chan);
395 static int pcl818_ai_cancel(struct comedi_device *dev,
396 struct comedi_subdevice *s);
397 static void start_pacer(struct comedi_device *dev, int mode,
398 unsigned int divisor1, unsigned int divisor2);
401 static int set_rtc_irq_bit(unsigned char bit);
402 static void rtc_dropped_irq(unsigned long data);
403 static int rtc_setfreq_irq(int freq);
407 ==============================================================================
408 ANALOG INPUT MODE0, 818 cards, slow version
410 static int pcl818_ai_insn_read(struct comedi_device *dev,
411 struct comedi_subdevice *s,
412 struct comedi_insn *insn, unsigned int *data)
417 /* software trigger, DMA and INT off */
418 outb(0, dev->iobase + PCL818_CONTROL);
421 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
424 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
426 for (n = 0; n < insn->n; n++) {
428 /* clear INT (conversion end) flag */
429 outb(0, dev->iobase + PCL818_CLRINT);
431 /* start conversion */
432 outb(0, dev->iobase + PCL818_AD_LO);
436 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
440 comedi_error(dev, "A/D insn timeout");
441 /* clear INT (conversion end) flag */
442 outb(0, dev->iobase + PCL818_CLRINT);
446 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
447 (inb(dev->iobase + PCL818_AD_LO) >> 4));
454 ==============================================================================
455 ANALOG OUTPUT MODE0, 818 cards
456 only one sample per call is supported
458 static int pcl818_ao_insn_read(struct comedi_device *dev,
459 struct comedi_subdevice *s,
460 struct comedi_insn *insn, unsigned int *data)
463 int chan = CR_CHAN(insn->chanspec);
465 for (n = 0; n < insn->n; n++) {
466 data[n] = devpriv->ao_readback[chan];
472 static int pcl818_ao_insn_write(struct comedi_device *dev,
473 struct comedi_subdevice *s,
474 struct comedi_insn *insn, unsigned int *data)
477 int chan = CR_CHAN(insn->chanspec);
479 for (n = 0; n < insn->n; n++) {
480 devpriv->ao_readback[chan] = data[n];
481 outb((data[n] & 0x000f) << 4, dev->iobase +
482 (chan ? PCL718_DA2_LO : PCL818_DA_LO));
483 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
484 (chan ? PCL718_DA2_HI : PCL818_DA_HI));
491 ==============================================================================
492 DIGITAL INPUT MODE0, 818 cards
494 only one sample per call is supported
496 static int pcl818_di_insn_bits(struct comedi_device *dev,
497 struct comedi_subdevice *s,
498 struct comedi_insn *insn, unsigned int *data)
503 data[1] = inb(dev->iobase + PCL818_DI_LO) |
504 (inb(dev->iobase + PCL818_DI_HI) << 8);
510 ==============================================================================
511 DIGITAL OUTPUT MODE0, 818 cards
513 only one sample per call is supported
515 static int pcl818_do_insn_bits(struct comedi_device *dev,
516 struct comedi_subdevice *s,
517 struct comedi_insn *insn, unsigned int *data)
522 s->state &= ~data[0];
523 s->state |= (data[0] & data[1]);
525 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
526 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
534 ==============================================================================
535 analog input interrupt mode 1 & 3, 818 cards
536 one sample per interrupt version
538 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
540 struct comedi_device *dev = d;
541 struct comedi_subdevice *s = dev->subdevices + 0;
543 int timeout = 50; /* wait max 50us */
546 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
550 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
551 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
552 pcl818_ai_cancel(dev, s);
553 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
554 comedi_event(dev, s);
558 low = inb(dev->iobase + PCL818_AD_LO);
559 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
560 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
562 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
564 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
566 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
567 pcl818_ai_cancel(dev, s);
568 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
569 comedi_event(dev, s);
572 devpriv->act_chanlist_pos++;
573 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
574 devpriv->act_chanlist_pos = 0;
576 s->async->cur_chan++;
577 if (s->async->cur_chan >= devpriv->ai_n_chan) {
579 s->async->cur_chan = 0;
580 devpriv->ai_act_scan--;
583 if (!devpriv->neverending_ai) {
584 if (devpriv->ai_act_scan == 0) { /* all data sampled */
585 pcl818_ai_cancel(dev, s);
586 s->async->events |= COMEDI_CB_EOA;
589 comedi_event(dev, s);
594 ==============================================================================
595 analog input dma mode 1 & 3, 818 cards
597 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
599 struct comedi_device *dev = d;
600 struct comedi_subdevice *s = dev->subdevices + 0;
605 disable_dma(devpriv->dma);
606 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
607 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
608 set_dma_mode(devpriv->dma, DMA_MODE_READ);
609 flags = claim_dma_lock();
610 set_dma_addr(devpriv->dma,
611 devpriv->hwdmaptr[devpriv->next_dma_buf]);
612 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
613 set_dma_count(devpriv->dma,
614 devpriv->hwdmasize[devpriv->
617 set_dma_count(devpriv->dma, devpriv->last_dma_run);
619 release_dma_lock(flags);
620 enable_dma(devpriv->dma);
622 printk("comedi: A/D mode1/3 IRQ \n");
624 devpriv->dma_runs_to_end--;
625 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
626 ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
628 len = devpriv->hwdmasize[0] >> 1;
631 for (i = 0; i < len; i++) {
632 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
634 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
636 devpriv->act_chanlist[devpriv->act_chanlist_pos],
637 devpriv->act_chanlist_pos);
638 pcl818_ai_cancel(dev, s);
639 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
640 comedi_event(dev, s);
644 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
646 devpriv->act_chanlist_pos++;
647 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
648 devpriv->act_chanlist_pos = 0;
650 s->async->cur_chan++;
651 if (s->async->cur_chan >= devpriv->ai_n_chan) {
652 s->async->cur_chan = 0;
653 devpriv->ai_act_scan--;
656 if (!devpriv->neverending_ai)
657 if (devpriv->ai_act_scan == 0) { /* all data sampled */
658 pcl818_ai_cancel(dev, s);
659 s->async->events |= COMEDI_CB_EOA;
660 comedi_event(dev, s);
661 /* printk("done int ai13 dma\n"); */
667 comedi_event(dev, s);
673 ==============================================================================
674 analog input dma mode 1 & 3 over RTC, 818 cards
676 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
678 struct comedi_device *dev = d;
679 struct comedi_subdevice *s = dev->subdevices + 0;
681 unsigned int top1, top2, i, bufptr;
683 short *dmabuf = (short *)devpriv->dmabuf[0];
686 switch (devpriv->ai_mode) {
687 case INT_TYPE_AI1_DMA_RTC:
688 case INT_TYPE_AI3_DMA_RTC:
689 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
690 mod_timer(&devpriv->rtc_irq_timer,
691 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
693 for (i = 0; i < 10; i++) {
694 top1 = get_dma_residue(devpriv->dma);
695 top2 = get_dma_residue(devpriv->dma);
702 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
704 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
706 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
708 return IRQ_HANDLED; /* exit=no new samples from last call */
710 i = devpriv->last_top_dma - 1;
711 i &= (devpriv->dmasamplsize - 1);
713 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
714 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
715 /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
716 pcl818_ai_cancel(dev, s);
717 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
718 comedi_event(dev, s);
721 /* printk("r %ld ",ofs_dats); */
723 bufptr = devpriv->last_top_dma;
725 for (i = 0; i < ofs_dats; i++) {
726 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
728 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
729 (dmabuf[bufptr] & 0xf),
731 act_chanlist[devpriv->act_chanlist_pos]);
732 pcl818_ai_cancel(dev, s);
734 COMEDI_CB_EOA | COMEDI_CB_ERROR;
735 comedi_event(dev, s);
739 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
740 bufptr &= (devpriv->dmasamplsize - 1);
742 devpriv->act_chanlist_pos++;
743 if (devpriv->act_chanlist_pos >=
744 devpriv->act_chanlist_len) {
745 devpriv->act_chanlist_pos = 0;
747 s->async->cur_chan++;
748 if (s->async->cur_chan >= devpriv->ai_n_chan) {
749 s->async->cur_chan = 0;
750 devpriv->ai_act_scan--;
753 if (!devpriv->neverending_ai)
754 if (devpriv->ai_act_scan == 0) { /* all data sampled */
755 pcl818_ai_cancel(dev, s);
756 s->async->events |= COMEDI_CB_EOA;
757 comedi_event(dev, s);
758 /* printk("done int ai13 dma\n"); */
763 devpriv->last_top_dma = bufptr;
765 bufptr &= (devpriv->dmasamplsize - 1);
766 dmabuf[bufptr] = MAGIC_DMA_WORD;
767 comedi_event(dev, s);
778 ==============================================================================
779 analog input interrupt mode 1 & 3, 818HD/HG cards
781 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
783 struct comedi_device *dev = d;
784 struct comedi_subdevice *s = dev->subdevices + 0;
787 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
789 lo = inb(dev->iobase + PCL818_FI_STATUS);
792 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
793 pcl818_ai_cancel(dev, s);
794 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
795 comedi_event(dev, s);
800 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
801 pcl818_ai_cancel(dev, s);
802 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
803 comedi_event(dev, s);
813 for (i = 0; i < len; i++) {
814 lo = inb(dev->iobase + PCL818_FI_DATALO);
815 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
817 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
819 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
820 pcl818_ai_cancel(dev, s);
821 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
822 comedi_event(dev, s);
826 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
828 devpriv->act_chanlist_pos++;
829 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
830 devpriv->act_chanlist_pos = 0;
832 s->async->cur_chan++;
833 if (s->async->cur_chan >= devpriv->ai_n_chan) {
834 s->async->cur_chan = 0;
835 devpriv->ai_act_scan--;
838 if (!devpriv->neverending_ai)
839 if (devpriv->ai_act_scan == 0) { /* all data sampled */
840 pcl818_ai_cancel(dev, s);
841 s->async->events |= COMEDI_CB_EOA;
842 comedi_event(dev, s);
848 comedi_event(dev, s);
853 ==============================================================================
856 static irqreturn_t interrupt_pcl818(int irq, void *d)
858 struct comedi_device *dev = d;
860 if (!dev->attached) {
861 comedi_error(dev, "premature interrupt");
866 if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
867 if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
868 devpriv->ai_act_scan > 0)) &&
869 (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
870 devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
871 /* The cleanup from ai_cancel() has been delayed
872 until now because the card doesn't seem to like
873 being reprogrammed while a DMA transfer is in
876 struct comedi_subdevice *s = dev->subdevices + 0;
877 devpriv->ai_act_scan = 0;
878 devpriv->neverending_ai = 0;
879 pcl818_ai_cancel(dev, s);
882 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
887 switch (devpriv->ai_mode) {
888 case INT_TYPE_AI1_DMA:
889 case INT_TYPE_AI3_DMA:
890 return interrupt_pcl818_ai_mode13_dma(irq, d);
891 case INT_TYPE_AI1_INT:
892 case INT_TYPE_AI3_INT:
893 return interrupt_pcl818_ai_mode13_int(irq, d);
894 case INT_TYPE_AI1_FIFO:
895 case INT_TYPE_AI3_FIFO:
896 return interrupt_pcl818_ai_mode13_fifo(irq, d);
897 #ifdef PCL818_MODE13_AO
898 case INT_TYPE_AO1_INT:
899 case INT_TYPE_AO3_INT:
900 return interrupt_pcl818_ao_mode13_int(irq, d);
906 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
908 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
909 || (!devpriv->ai_mode)) {
910 comedi_error(dev, "bad IRQ!");
914 comedi_error(dev, "IRQ from unknown source!");
919 ==============================================================================
920 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
922 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
923 struct comedi_subdevice *s)
928 printk("mode13dma_int, mode: %d\n", mode);
929 disable_dma(devpriv->dma); /* disable dma */
930 bytes = devpriv->hwdmasize[0];
931 if (!devpriv->neverending_ai) {
932 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
933 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
934 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
935 devpriv->dma_runs_to_end--;
936 if (devpriv->dma_runs_to_end >= 0)
937 bytes = devpriv->hwdmasize[0];
940 devpriv->next_dma_buf = 0;
941 set_dma_mode(devpriv->dma, DMA_MODE_READ);
942 flags = claim_dma_lock();
943 clear_dma_ff(devpriv->dma);
944 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
945 set_dma_count(devpriv->dma, bytes);
946 release_dma_lock(flags);
947 enable_dma(devpriv->dma);
950 devpriv->ai_mode = INT_TYPE_AI1_DMA;
951 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
953 devpriv->ai_mode = INT_TYPE_AI3_DMA;
954 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
960 ==============================================================================
961 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
963 static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
964 struct comedi_subdevice *s)
969 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
970 flags = claim_dma_lock();
971 clear_dma_ff(devpriv->dma);
972 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
973 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
974 release_dma_lock(flags);
975 enable_dma(devpriv->dma);
976 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
977 pole = (short *)devpriv->dmabuf[0];
978 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
979 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
981 devpriv->rtc_freq = rtc_setfreq_irq(2048);
982 devpriv->rtc_irq_timer.expires =
983 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
984 devpriv->rtc_irq_timer.data = (unsigned long)dev;
985 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
987 add_timer(&devpriv->rtc_irq_timer);
991 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
992 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
994 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
995 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
1001 ==============================================================================
1002 ANALOG INPUT MODE 1 or 3, 818 cards
1004 static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
1005 struct comedi_subdevice *s)
1007 struct comedi_cmd *cmd = &s->async->cmd;
1008 int divisor1 = 0, divisor2 = 0;
1009 unsigned int seglen;
1011 printk("pcl818_ai_cmd_mode()\n");
1012 if ((!dev->irq) && (!devpriv->dma_rtc)) {
1013 comedi_error(dev, "IRQ not defined!");
1017 if (devpriv->irq_blocked)
1020 start_pacer(dev, -1, 0, 0); /* stop pacer */
1022 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
1023 devpriv->ai_n_chan);
1026 setup_channel_list(dev, s, devpriv->ai_chanlist,
1027 devpriv->ai_n_chan, seglen);
1031 devpriv->ai_act_scan = devpriv->ai_scans;
1032 devpriv->ai_act_chan = 0;
1033 devpriv->irq_blocked = 1;
1034 devpriv->irq_was_now_closed = 0;
1035 devpriv->neverending_ai = 0;
1036 devpriv->act_chanlist_pos = 0;
1037 devpriv->dma_runs_to_end = 0;
1039 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
1040 devpriv->neverending_ai = 1; /* well, user want neverending */
1043 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1044 &divisor2, &cmd->convert_arg,
1045 TRIG_ROUND_NEAREST);
1046 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
1050 if (divisor2 == 1) {
1056 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1058 switch (devpriv->dma) {
1061 if (devpriv->dma_rtc == 0) {
1062 pcl818_ai_mode13dma_int(mode, dev, s);
1066 pcl818_ai_mode13dma_rtc(mode, dev, s);
1075 if (!devpriv->usefifo) {
1077 /* printk("IRQ\n"); */
1079 devpriv->ai_mode = INT_TYPE_AI1_INT;
1081 outb(0x83 | (dev->irq << 4),
1082 dev->iobase + PCL818_CONTROL);
1084 devpriv->ai_mode = INT_TYPE_AI3_INT;
1086 outb(0x82 | (dev->irq << 4),
1087 dev->iobase + PCL818_CONTROL);
1092 outb(1, dev->iobase + PCL818_FI_ENABLE);
1094 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1096 outb(0x03, dev->iobase + PCL818_CONTROL);
1098 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1099 outb(0x02, dev->iobase + PCL818_CONTROL);
1104 start_pacer(dev, mode, divisor1, divisor2);
1107 switch (devpriv->ai_mode) {
1108 case INT_TYPE_AI1_DMA_RTC:
1109 case INT_TYPE_AI3_DMA_RTC:
1110 set_rtc_irq_bit(1); /* start RTC */
1114 printk("pcl818_ai_cmd_mode() end\n");
1120 ==============================================================================
1121 ANALOG OUTPUT MODE 1 or 3, 818 cards
1123 #ifdef PCL818_MODE13_AO
1124 static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
1125 struct comedi_subdevice *s, comedi_trig * it)
1127 int divisor1 = 0, divisor2 = 0;
1130 comedi_error(dev, "IRQ not defined!");
1134 if (devpriv->irq_blocked)
1137 start_pacer(dev, -1, 0, 0); /* stop pacer */
1139 devpriv->int13_act_scan = it->n;
1140 devpriv->int13_act_chan = 0;
1141 devpriv->irq_blocked = 1;
1142 devpriv->irq_was_now_closed = 0;
1143 devpriv->neverending_ai = 0;
1144 devpriv->act_chanlist_pos = 0;
1147 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1148 &divisor2, &it->trigvar,
1149 TRIG_ROUND_NEAREST);
1150 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1154 if (divisor2 == 1) {
1160 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1162 devpriv->int818_mode = INT_TYPE_AO1_INT;
1163 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1165 devpriv->int818_mode = INT_TYPE_AO3_INT;
1166 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1169 start_pacer(dev, mode, divisor1, divisor2);
1175 ==============================================================================
1176 ANALOG OUTPUT MODE 1, 818 cards
1178 static int pcl818_ao_mode1(struct comedi_device *dev,
1179 struct comedi_subdevice *s, comedi_trig * it)
1181 return pcl818_ao_mode13(1, dev, s, it);
1185 ==============================================================================
1186 ANALOG OUTPUT MODE 3, 818 cards
1188 static int pcl818_ao_mode3(struct comedi_device *dev,
1189 struct comedi_subdevice *s, comedi_trig * it)
1191 return pcl818_ao_mode13(3, dev, s, it);
1197 ==============================================================================
1198 Start/stop pacer onboard pacer
1200 static void start_pacer(struct comedi_device *dev, int mode,
1201 unsigned int divisor1, unsigned int divisor2)
1203 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1204 outb(0x74, dev->iobase + PCL818_CTRCTL);
1208 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1209 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1210 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1211 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1216 ==============================================================================
1217 Check if channel list from user is builded correctly
1218 If it's ok, then program scan/gain logic
1220 static int check_channel_list(struct comedi_device *dev,
1221 struct comedi_subdevice *s,
1222 unsigned int *chanlist, unsigned int n_chan)
1224 unsigned int chansegment[16];
1225 unsigned int i, nowmustbechan, seglen, segpos;
1227 /* correct channel and range number check itself comedi/range.c */
1229 comedi_error(dev, "range/channel list is empty!");
1234 /* first channel is everytime ok */
1235 chansegment[0] = chanlist[0];
1236 /* build part of chanlist */
1237 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1239 /* printk("%d. %d * %d\n",i,
1240 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1242 /* we detect loop, this must by finish */
1244 if (chanlist[0] == chanlist[i])
1247 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1248 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */
1250 ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1251 dev->minor, i, CR_CHAN(chanlist[i]),
1252 nowmustbechan, CR_CHAN(chanlist[0]));
1255 /* well, this is next correct channel in list */
1256 chansegment[i] = chanlist[i];
1259 /* check whole chanlist */
1260 for (i = 0, segpos = 0; i < n_chan; i++) {
1261 /* 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])); */
1262 if (chanlist[i] != chansegment[i % seglen]) {
1264 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1265 dev->minor, i, CR_CHAN(chansegment[i]),
1266 CR_RANGE(chansegment[i]),
1267 CR_AREF(chansegment[i]),
1268 CR_CHAN(chanlist[i % seglen]),
1269 CR_RANGE(chanlist[i % seglen]),
1270 CR_AREF(chansegment[i % seglen]));
1271 return 0; /* chan/gain list is strange */
1277 printk("check_channel_list: seglen %d\n", seglen);
1281 static void setup_channel_list(struct comedi_device *dev,
1282 struct comedi_subdevice *s,
1283 unsigned int *chanlist, unsigned int n_chan,
1284 unsigned int seglen)
1288 devpriv->act_chanlist_len = seglen;
1289 devpriv->act_chanlist_pos = 0;
1291 for (i = 0; i < seglen; i++) { /* store range list to card */
1292 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1293 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1294 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1299 /* select channel interval to scan */
1300 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1302 dev->iobase + PCL818_MUX);
1306 ==============================================================================
1307 Check if board is switched to SE (1) or DIFF(0) mode
1309 static int check_single_ended(unsigned int port)
1311 if (inb(port + PCL818_STATUS) & 0x20) {
1319 ==============================================================================
1321 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1322 struct comedi_cmd *cmd)
1325 int tmp, divisor1 = 0, divisor2 = 0;
1327 /* step 1: make sure trigger sources are trivially valid */
1329 tmp = cmd->start_src;
1330 cmd->start_src &= TRIG_NOW;
1331 if (!cmd->start_src || tmp != cmd->start_src)
1334 tmp = cmd->scan_begin_src;
1335 cmd->scan_begin_src &= TRIG_FOLLOW;
1336 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1339 tmp = cmd->convert_src;
1340 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1341 if (!cmd->convert_src || tmp != cmd->convert_src)
1344 tmp = cmd->scan_end_src;
1345 cmd->scan_end_src &= TRIG_COUNT;
1346 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1349 tmp = cmd->stop_src;
1350 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1351 if (!cmd->stop_src || tmp != cmd->stop_src)
1358 /* step 2: make sure trigger sources are unique and mutually compatible */
1360 if (cmd->start_src != TRIG_NOW) {
1361 cmd->start_src = TRIG_NOW;
1364 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1365 cmd->scan_begin_src = TRIG_FOLLOW;
1368 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1371 if (cmd->scan_end_src != TRIG_COUNT) {
1372 cmd->scan_end_src = TRIG_COUNT;
1376 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1383 /* step 3: make sure arguments are trivially compatible */
1385 if (cmd->start_arg != 0) {
1390 if (cmd->scan_begin_arg != 0) {
1391 cmd->scan_begin_arg = 0;
1395 if (cmd->convert_src == TRIG_TIMER) {
1396 if (cmd->convert_arg < this_board->ns_min) {
1397 cmd->convert_arg = this_board->ns_min;
1400 } else { /* TRIG_EXT */
1401 if (cmd->convert_arg != 0) {
1402 cmd->convert_arg = 0;
1407 if (cmd->scan_end_arg != cmd->chanlist_len) {
1408 cmd->scan_end_arg = cmd->chanlist_len;
1411 if (cmd->stop_src == TRIG_COUNT) {
1412 if (!cmd->stop_arg) {
1416 } else { /* TRIG_NONE */
1417 if (cmd->stop_arg != 0) {
1427 /* step 4: fix up any arguments */
1429 if (cmd->convert_src == TRIG_TIMER) {
1430 tmp = cmd->convert_arg;
1431 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1432 &divisor2, &cmd->convert_arg,
1433 cmd->flags & TRIG_ROUND_MASK);
1434 if (cmd->convert_arg < this_board->ns_min)
1435 cmd->convert_arg = this_board->ns_min;
1436 if (tmp != cmd->convert_arg)
1444 /* step 5: complain about special chanlist considerations */
1446 if (cmd->chanlist) {
1447 if (!check_channel_list(dev, s, cmd->chanlist,
1449 return 5; /* incorrect channels list */
1456 ==============================================================================
1458 static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1460 struct comedi_cmd *cmd = &s->async->cmd;
1463 printk("pcl818_ai_cmd()\n");
1464 devpriv->ai_n_chan = cmd->chanlist_len;
1465 devpriv->ai_chanlist = cmd->chanlist;
1466 devpriv->ai_flags = cmd->flags;
1467 devpriv->ai_data_len = s->async->prealloc_bufsz;
1468 devpriv->ai_data = s->async->prealloc_buf;
1469 devpriv->ai_timer1 = 0;
1470 devpriv->ai_timer2 = 0;
1472 if (cmd->stop_src == TRIG_COUNT) {
1473 devpriv->ai_scans = cmd->stop_arg;
1475 devpriv->ai_scans = 0;
1478 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1479 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
1480 devpriv->ai_timer1 = cmd->convert_arg;
1481 retval = pcl818_ai_cmd_mode(1, dev, s);
1482 printk("pcl818_ai_cmd() end\n");
1485 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1486 return pcl818_ai_cmd_mode(3, dev, s);
1494 ==============================================================================
1495 cancel any mode 1-4 AI
1497 static int pcl818_ai_cancel(struct comedi_device *dev,
1498 struct comedi_subdevice *s)
1500 if (devpriv->irq_blocked > 0) {
1501 printk("pcl818_ai_cancel()\n");
1502 devpriv->irq_was_now_closed = 1;
1504 switch (devpriv->ai_mode) {
1506 case INT_TYPE_AI1_DMA_RTC:
1507 case INT_TYPE_AI3_DMA_RTC:
1508 set_rtc_irq_bit(0); /* stop RTC */
1509 del_timer(&devpriv->rtc_irq_timer);
1511 case INT_TYPE_AI1_DMA:
1512 case INT_TYPE_AI3_DMA:
1513 if (devpriv->neverending_ai ||
1514 (!devpriv->neverending_ai &&
1515 devpriv->ai_act_scan > 0)) {
1516 /* wait for running dma transfer to end, do cleanup in interrupt */
1519 disable_dma(devpriv->dma);
1520 case INT_TYPE_AI1_INT:
1521 case INT_TYPE_AI3_INT:
1522 case INT_TYPE_AI1_FIFO:
1523 case INT_TYPE_AI3_FIFO:
1524 #ifdef PCL818_MODE13_AO
1525 case INT_TYPE_AO1_INT:
1526 case INT_TYPE_AO3_INT:
1528 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1530 start_pacer(dev, -1, 0, 0);
1531 outb(0, dev->iobase + PCL818_AD_LO);
1532 inb(dev->iobase + PCL818_AD_LO);
1533 inb(dev->iobase + PCL818_AD_HI);
1534 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1535 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1536 if (devpriv->usefifo) { /* FIFO shutdown */
1537 outb(0, dev->iobase + PCL818_FI_INTCLR);
1538 outb(0, dev->iobase + PCL818_FI_FLUSH);
1539 outb(0, dev->iobase + PCL818_FI_ENABLE);
1541 devpriv->irq_blocked = 0;
1542 devpriv->last_int_sub = s;
1543 devpriv->neverending_ai = 0;
1544 devpriv->ai_mode = 0;
1545 devpriv->irq_was_now_closed = 0;
1551 printk("pcl818_ai_cancel() end\n");
1556 ==============================================================================
1559 static int pcl818_check(unsigned long iobase)
1561 outb(0x00, iobase + PCL818_MUX);
1563 if (inb(iobase + PCL818_MUX) != 0x00)
1564 return 1; /* there isn't card */
1565 outb(0x55, iobase + PCL818_MUX);
1567 if (inb(iobase + PCL818_MUX) != 0x55)
1568 return 1; /* there isn't card */
1569 outb(0x00, iobase + PCL818_MUX);
1571 outb(0x18, iobase + PCL818_CONTROL);
1573 if (inb(iobase + PCL818_CONTROL) != 0x18)
1574 return 1; /* there isn't card */
1575 return 0; /* ok, card exist */
1579 ==============================================================================
1580 reset whole PCL-818 cards
1582 static void pcl818_reset(struct comedi_device *dev)
1584 if (devpriv->usefifo) { /* FIFO shutdown */
1585 outb(0, dev->iobase + PCL818_FI_INTCLR);
1586 outb(0, dev->iobase + PCL818_FI_FLUSH);
1587 outb(0, dev->iobase + PCL818_FI_ENABLE);
1589 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
1590 outb(0, dev->iobase + PCL818_DA_HI);
1592 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
1593 outb(0, dev->iobase + PCL818_DO_LO);
1595 outb(0, dev->iobase + PCL818_CONTROL);
1596 outb(0, dev->iobase + PCL818_CNTENABLE);
1597 outb(0, dev->iobase + PCL818_MUX);
1598 outb(0, dev->iobase + PCL818_CLRINT);
1599 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1600 outb(0x70, dev->iobase + PCL818_CTRCTL);
1601 outb(0x30, dev->iobase + PCL818_CTRCTL);
1602 if (this_board->is_818) {
1603 outb(0, dev->iobase + PCL818_RANGE);
1605 outb(0, dev->iobase + PCL718_DA2_LO);
1606 outb(0, dev->iobase + PCL718_DA2_HI);
1612 ==============================================================================
1613 Enable(1)/disable(0) periodic interrupts from RTC
1615 static int set_rtc_irq_bit(unsigned char bit)
1618 unsigned long flags;
1622 if (RTC_timer_lock > 1)
1626 if (RTC_timer_lock < 0)
1628 if (RTC_timer_lock > 0)
1634 val = CMOS_READ(RTC_CONTROL);
1640 CMOS_WRITE(val, RTC_CONTROL);
1641 CMOS_READ(RTC_INTR_FLAGS);
1642 restore_flags(flags);
1647 ==============================================================================
1648 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1650 static void rtc_dropped_irq(unsigned long data)
1652 struct comedi_device *dev = (void *)data;
1653 unsigned long flags, tmp;
1655 switch (devpriv->int818_mode) {
1656 case INT_TYPE_AI1_DMA_RTC:
1657 case INT_TYPE_AI3_DMA_RTC:
1658 mod_timer(&devpriv->rtc_irq_timer,
1659 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1662 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1663 restore_flags(flags);
1669 ==============================================================================
1670 Set frequency of interrupts from RTC
1672 static int rtc_setfreq_irq(int freq)
1677 unsigned long flags;
1684 while (freq > (1 << tmp))
1687 rtc_freq = 1 << tmp;
1691 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1693 CMOS_WRITE(val, RTC_FREQ_SELECT);
1694 restore_flags(flags);
1700 ==============================================================================
1701 Free any resources that we have claimed
1703 static void free_resources(struct comedi_device *dev)
1705 /* printk("free_resource()\n"); */
1707 pcl818_ai_cancel(dev, devpriv->sub_ai);
1710 free_dma(devpriv->dma);
1711 if (devpriv->dmabuf[0])
1712 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1713 if (devpriv->dmabuf[1])
1714 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1716 if (devpriv->rtc_irq)
1717 free_irq(devpriv->rtc_irq, dev);
1718 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1719 if (devpriv->rtc_iobase)
1720 release_region(devpriv->rtc_iobase,
1721 devpriv->rtc_iosize);
1723 if (devpriv->dma_rtc)
1729 free_irq(dev->irq, dev);
1731 release_region(dev->iobase, devpriv->io_range);
1732 /* printk("free_resource() end\n"); */
1736 ==============================================================================
1741 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1744 unsigned long iobase;
1747 unsigned long pages;
1748 struct comedi_subdevice *s;
1750 ret = alloc_private(dev, sizeof(struct pcl818_private));
1752 return ret; /* Can't alloc mem */
1754 /* claim our I/O space */
1755 iobase = it->options[0];
1756 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1757 dev->minor, this_board->name, iobase);
1758 devpriv->io_range = this_board->io_range;
1759 if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */
1760 devpriv->io_range = PCLx1xFIFO_RANGE;
1761 devpriv->usefifo = 1;
1763 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1764 printk("I/O port conflict\n");
1768 dev->iobase = iobase;
1770 if (pcl818_check(iobase)) {
1771 printk(", I can't detect board. FAIL!\n");
1775 /* set up some name stuff */
1776 dev->board_name = this_board->name;
1779 if (this_board->IRQbits != 0) { /* board support IRQ */
1780 irq = it->options[1];
1781 if (irq) { /* we want to use IRQ */
1782 if (((1 << irq) & this_board->IRQbits) == 0) {
1784 (", IRQ %u is out of allowed range, DISABLING IT",
1786 irq = 0; /* Bad IRQ */
1789 (irq, interrupt_pcl818, 0, "pcl818", dev)) {
1791 (", unable to allocate IRQ %u, DISABLING IT",
1793 irq = 0; /* Can't use IRQ */
1795 printk(", irq=%u", irq);
1803 devpriv->irq_free = 1;
1804 } /* 1=we have allocated irq */
1806 devpriv->irq_free = 0;
1808 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1809 devpriv->ai_mode = 0; /* mode of irq */
1812 /* grab RTC for DMA operations */
1813 devpriv->dma_rtc = 0;
1814 if (it->options[2] > 0) { /* we want to use DMA */
1815 if (RTC_lock == 0) {
1816 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1820 devpriv->rtc_iobase = RTC_PORT(0);
1821 devpriv->rtc_iosize = RTC_IO_EXTENT;
1823 if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
1824 "pcl818 DMA (RTC)", dev)) {
1825 devpriv->dma_rtc = 1;
1826 devpriv->rtc_irq = RTC_IRQ;
1827 printk(", dma_irq=%u", devpriv->rtc_irq);
1830 if (RTC_lock == 0) {
1831 if (devpriv->rtc_iobase)
1832 release_region(devpriv->rtc_iobase,
1833 devpriv->rtc_iosize);
1835 devpriv->rtc_iobase = 0;
1836 devpriv->rtc_iosize = 0;
1845 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1846 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1847 if (this_board->DMAbits != 0) { /* board support DMA */
1848 dma = it->options[2];
1850 goto no_dma; /* DMA disabled */
1851 if (((1 << dma) & this_board->DMAbits) == 0) {
1852 printk(", DMA is out of allowed range, FAIL!\n");
1853 return -EINVAL; /* Bad DMA */
1855 ret = request_dma(dma, "pcl818");
1857 printk(", unable to allocate DMA %u, FAIL!\n", dma);
1858 return -EBUSY; /* DMA isn't free */
1861 printk(", dma=%u", dma);
1862 pages = 2; /* we need 16KB */
1863 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1864 if (!devpriv->dmabuf[0]) {
1865 printk(", unable to allocate DMA buffer, FAIL!\n");
1866 /* maybe experiment with try_to_free_pages() will help .... */
1867 return -EBUSY; /* no buffer :-( */
1869 devpriv->dmapages[0] = pages;
1870 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1871 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1872 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1873 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1874 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1875 if (!devpriv->dmabuf[1]) {
1877 (", unable to allocate DMA buffer, FAIL!\n");
1880 devpriv->dmapages[1] = pages;
1881 devpriv->hwdmaptr[1] =
1882 virt_to_bus((void *)devpriv->dmabuf[1]);
1883 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1889 ret = alloc_subdevices(dev, 4);
1893 s = dev->subdevices + 0;
1894 if (!this_board->n_aichan_se) {
1895 s->type = COMEDI_SUBD_UNUSED;
1897 s->type = COMEDI_SUBD_AI;
1898 devpriv->sub_ai = s;
1899 s->subdev_flags = SDF_READABLE;
1900 if (check_single_ended(dev->iobase)) {
1901 s->n_chan = this_board->n_aichan_se;
1902 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1903 printk(", %dchans S.E. DAC", s->n_chan);
1905 s->n_chan = this_board->n_aichan_diff;
1906 s->subdev_flags |= SDF_DIFF;
1907 printk(", %dchans DIFF DAC", s->n_chan);
1909 s->maxdata = this_board->ai_maxdata;
1910 s->len_chanlist = s->n_chan;
1911 s->range_table = this_board->ai_range_type;
1912 s->cancel = pcl818_ai_cancel;
1913 s->insn_read = pcl818_ai_insn_read;
1914 if ((irq) || (devpriv->dma_rtc)) {
1915 dev->read_subdev = s;
1916 s->subdev_flags |= SDF_CMD_READ;
1917 s->do_cmdtest = ai_cmdtest;
1920 if (this_board->is_818) {
1921 if ((it->options[4] == 1) || (it->options[4] == 10))
1922 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
1924 switch (it->options[4]) {
1926 s->range_table = &range_bipolar10;
1929 s->range_table = &range_bipolar5;
1932 s->range_table = &range_bipolar2_5;
1935 s->range_table = &range718_bipolar1;
1938 s->range_table = &range718_bipolar0_5;
1941 s->range_table = &range_unipolar10;
1944 s->range_table = &range_unipolar5;
1947 s->range_table = &range718_unipolar2;
1950 s->range_table = &range718_unipolar1;
1953 s->range_table = &range_unknown;
1959 s = dev->subdevices + 1;
1960 if (!this_board->n_aochan) {
1961 s->type = COMEDI_SUBD_UNUSED;
1963 s->type = COMEDI_SUBD_AO;
1964 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1965 s->n_chan = this_board->n_aochan;
1966 s->maxdata = this_board->ao_maxdata;
1967 s->len_chanlist = this_board->n_aochan;
1968 s->range_table = this_board->ao_range_type;
1969 s->insn_read = pcl818_ao_insn_read;
1970 s->insn_write = pcl818_ao_insn_write;
1972 #ifdef PCL818_MODE13_AO
1974 s->trig[1] = pcl818_ao_mode1;
1975 s->trig[3] = pcl818_ao_mode3;
1979 if (this_board->is_818) {
1980 if ((it->options[4] == 1) || (it->options[4] == 10))
1981 s->range_table = &range_unipolar10;
1982 if (it->options[4] == 2)
1983 s->range_table = &range_unknown;
1985 if ((it->options[5] == 1) || (it->options[5] == 10))
1986 s->range_table = &range_unipolar10;
1987 if (it->options[5] == 2)
1988 s->range_table = &range_unknown;
1992 s = dev->subdevices + 2;
1993 if (!this_board->n_dichan) {
1994 s->type = COMEDI_SUBD_UNUSED;
1996 s->type = COMEDI_SUBD_DI;
1997 s->subdev_flags = SDF_READABLE;
1998 s->n_chan = this_board->n_dichan;
2000 s->len_chanlist = this_board->n_dichan;
2001 s->range_table = &range_digital;
2002 s->insn_bits = pcl818_di_insn_bits;
2005 s = dev->subdevices + 3;
2006 if (!this_board->n_dochan) {
2007 s->type = COMEDI_SUBD_UNUSED;
2009 s->type = COMEDI_SUBD_DO;
2010 s->subdev_flags = SDF_WRITABLE;
2011 s->n_chan = this_board->n_dochan;
2013 s->len_chanlist = this_board->n_dochan;
2014 s->range_table = &range_digital;
2015 s->insn_bits = pcl818_do_insn_bits;
2018 /* select 1/10MHz oscilator */
2019 if ((it->options[3] == 0) || (it->options[3] == 10)) {
2020 devpriv->i8253_osc_base = 100;
2022 devpriv->i8253_osc_base = 1000;
2025 /* max sampling speed */
2026 devpriv->ns_min = this_board->ns_min;
2028 if (!this_board->is_818) {
2029 if ((it->options[6] == 1) || (it->options[6] == 100))
2030 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
2041 ==============================================================================
2044 static int pcl818_detach(struct comedi_device *dev)
2046 /* printk("comedi%d: pcl818: remove\n", dev->minor); */
2047 free_resources(dev);
2051 MODULE_AUTHOR("Comedi http://www.comedi.org");
2052 MODULE_DESCRIPTION("Comedi low-level driver");
2053 MODULE_LICENSE("GPL");