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 unknow (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 unknow (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 unknow (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 unknow (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/delay.h>
110 /* #define PCL818_MODE13_AO 1 */
112 /* boards constants */
114 #define boardPCL818L 0
115 #define boardPCL818H 1
116 #define boardPCL818HD 2
117 #define boardPCL818HG 3
118 #define boardPCL818 4
119 #define boardPCL718 5
122 #define PCLx1x_RANGE 16
123 /* IO space len if we use FIFO */
124 #define PCLx1xFIFO_RANGE 32
126 /* W: clear INT request */
127 #define PCL818_CLRINT 8
128 /* R: return status byte */
129 #define PCL818_STATUS 8
130 /* R: A/D high byte W: A/D range control */
131 #define PCL818_RANGE 1
132 /* R: next mux scan channel W: mux scan channel & range control pointer */
134 /* R/W: operation control register */
135 #define PCL818_CONTROL 9
136 /* W: counter enable */
137 #define PCL818_CNTENABLE 10
139 /* R: low byte of A/D W: soft A/D trigger */
140 #define PCL818_AD_LO 0
141 /* R: high byte of A/D W: A/D range control */
142 #define PCL818_AD_HI 1
143 /* W: D/A low&high byte */
144 #define PCL818_DA_LO 4
145 #define PCL818_DA_HI 5
146 /* R: low&high byte of DI */
147 #define PCL818_DI_LO 3
148 #define PCL818_DI_HI 11
149 /* W: low&high byte of DO */
150 #define PCL818_DO_LO 3
151 #define PCL818_DO_HI 11
152 /* W: PCL718 second D/A */
153 #define PCL718_DA2_LO 6
154 #define PCL718_DA2_HI 7
156 #define PCL818_CTR0 12
157 #define PCL818_CTR1 13
158 #define PCL818_CTR2 14
159 /* W: counter control */
160 #define PCL818_CTRCTL 15
162 /* W: fifo enable/disable */
163 #define PCL818_FI_ENABLE 6
164 /* W: fifo interrupt clear */
165 #define PCL818_FI_INTCLR 20
166 /* W: fifo interrupt clear */
167 #define PCL818_FI_FLUSH 25
169 #define PCL818_FI_STATUS 25
170 /* R: one record from FIFO */
171 #define PCL818_FI_DATALO 23
172 #define PCL818_FI_DATAHI 23
174 /* type of interrupt handler */
175 #define INT_TYPE_AI1_INT 1
176 #define INT_TYPE_AI1_DMA 2
177 #define INT_TYPE_AI1_FIFO 3
178 #define INT_TYPE_AI3_INT 4
179 #define INT_TYPE_AI3_DMA 5
180 #define INT_TYPE_AI3_FIFO 6
181 #ifdef PCL818_MODE13_AO
182 #define INT_TYPE_AO1_INT 7
183 #define INT_TYPE_AO3_INT 8
188 #define INT_TYPE_AI1_DMA_RTC 9
189 #define INT_TYPE_AI3_DMA_RTC 10
192 #define RTC_IO_EXTENT 0x10
195 #define MAGIC_DMA_WORD 0x5a5a
197 static const struct comedi_lrange range_pcl818h_ai = { 9, {
210 static const struct comedi_lrange range_pcl818hg_ai = { 10, {
226 static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
234 static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
242 static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
243 static const struct comedi_lrange range718_bipolar0_5 = { 1, {BIP_RANGE(0.5),} };
244 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
245 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
247 static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * it);
248 static int pcl818_detach(struct comedi_device * dev);
251 static int RTC_lock = 0; /* RTC lock */
252 static int RTC_timer_lock = 0; /* RTC int lock */
255 struct pcl818_board {
257 const char *name; /* driver name */
258 int n_ranges; /* len of range list */
259 int n_aichan_se; /* num of A/D chans in single ended mode */
260 int n_aichan_diff; /* num of A/D chans in diferencial mode */
261 unsigned int ns_min; /* minimal alllowed delay between samples (in ns) */
262 int n_aochan; /* num of D/A chans */
263 int n_dichan; /* num of DI chans */
264 int n_dochan; /* num of DO chans */
265 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
266 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
267 unsigned int io_range; /* len of IO space */
268 unsigned int IRQbits; /* allowed interrupts */
269 unsigned int DMAbits; /* allowed DMA chans */
270 int ai_maxdata; /* maxdata for A/D */
271 int ao_maxdata; /* maxdata for D/A */
272 unsigned char fifo; /* 1=board has FIFO */
277 static const struct pcl818_board boardtypes[] = {
278 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
279 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
280 0x0a, 0xfff, 0xfff, 0, 1},
281 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
282 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
283 0x0a, 0xfff, 0xfff, 0, 1},
284 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
285 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
286 0x0a, 0xfff, 0xfff, 1, 1},
287 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
288 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
289 0x0a, 0xfff, 0xfff, 1, 1},
290 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
291 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
292 0x0a, 0xfff, 0xfff, 0, 1},
293 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
294 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
295 0x0a, 0xfff, 0xfff, 0, 0},
297 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
298 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
299 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
302 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
304 static struct comedi_driver driver_pcl818 = {
305 driver_name:"pcl818",
307 attach:pcl818_attach,
308 detach:pcl818_detach,
309 board_name:&boardtypes[0].name,
310 num_names:n_boardtypes,
311 offset:sizeof(struct pcl818_board),
314 COMEDI_INITCLEANUP(driver_pcl818);
316 struct pcl818_private {
318 unsigned int dma; /* used DMA, 0=don't use DMA */
319 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
320 unsigned int io_range;
322 unsigned long rtc_iobase; /* RTC port region */
323 unsigned int rtc_iosize;
324 unsigned int rtc_irq;
325 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
326 unsigned long rtc_freq; /* RTC int freq */
327 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
329 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
330 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
331 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
332 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
333 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
334 unsigned int last_top_dma; /* DMA pointer in last RTC int */
335 int next_dma_buf; /* which DMA buffer will be used next round */
336 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
337 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
338 unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
339 unsigned int ns_min; /* manimal alllowed delay between samples (in us) for actual card */
340 int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
341 int irq_free; /* 1=have allocated IRQ */
342 int irq_blocked; /* 1=IRQ now uses any subdev */
343 int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
344 int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
345 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
346 int ai_act_scan; /* how many scans we finished */
347 int ai_act_chan; /* actual position in actual scan */
348 unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
349 unsigned int act_chanlist_len; /* how long is actual MUX list */
350 unsigned int act_chanlist_pos; /* actual position in MUX list */
351 unsigned int ai_scans; /* len of scanlist */
352 unsigned int ai_n_chan; /* how many channels is measured */
353 unsigned int *ai_chanlist; /* actaul chanlist */
354 unsigned int ai_flags; /* flaglist */
355 unsigned int ai_data_len; /* len of data buffer */
356 short *ai_data; /* data buffer */
357 unsigned int ai_timer1; /* timers */
358 unsigned int ai_timer2;
359 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
360 unsigned char usefifo; /* 1=use fifo */
361 unsigned int ao_readback[2];
365 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
366 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
369 #define devpriv ((struct pcl818_private *)dev->private)
370 #define this_board ((const struct pcl818_board *)dev->board_ptr)
373 ==============================================================================
375 static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
376 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen);
377 static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
378 unsigned int *chanlist, unsigned int n_chan);
380 static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
381 static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
382 unsigned int divisor2);
385 static int set_rtc_irq_bit(unsigned char bit);
386 static void rtc_dropped_irq(unsigned long data);
387 static int rtc_setfreq_irq(int freq);
391 ==============================================================================
392 ANALOG INPUT MODE0, 818 cards, slow version
394 static int pcl818_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
395 struct comedi_insn * insn, unsigned int * data)
400 /* software trigger, DMA and INT off */
401 outb(0, dev->iobase + PCL818_CONTROL);
404 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
407 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
409 for (n = 0; n < insn->n; n++) {
411 /* clear INT (conversion end) flag */
412 outb(0, dev->iobase + PCL818_CLRINT);
414 /* start conversion */
415 outb(0, dev->iobase + PCL818_AD_LO);
419 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
423 comedi_error(dev, "A/D insn timeout");
424 /* clear INT (conversion end) flag */
425 outb(0, dev->iobase + PCL818_CLRINT);
429 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
430 (inb(dev->iobase + PCL818_AD_LO) >> 4));
437 ==============================================================================
438 ANALOG OUTPUT MODE0, 818 cards
439 only one sample per call is supported
441 static int pcl818_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
442 struct comedi_insn * insn, unsigned int * data)
445 int chan = CR_CHAN(insn->chanspec);
447 for (n = 0; n < insn->n; n++) {
448 data[n] = devpriv->ao_readback[chan];
454 static int pcl818_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
455 struct comedi_insn * insn, unsigned int * data)
458 int chan = CR_CHAN(insn->chanspec);
460 for (n = 0; n < insn->n; n++) {
461 devpriv->ao_readback[chan] = data[n];
462 outb((data[n] & 0x000f) << 4, dev->iobase +
463 (chan) ? PCL718_DA2_LO : PCL818_DA_LO);
464 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
465 (chan) ? PCL718_DA2_HI : PCL818_DA_HI);
472 ==============================================================================
473 DIGITAL INPUT MODE0, 818 cards
475 only one sample per call is supported
477 static int pcl818_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
478 struct comedi_insn * insn, unsigned int * data)
483 data[1] = inb(dev->iobase + PCL818_DI_LO) |
484 (inb(dev->iobase + PCL818_DI_HI) << 8);
490 ==============================================================================
491 DIGITAL OUTPUT MODE0, 818 cards
493 only one sample per call is supported
495 static int pcl818_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
496 struct comedi_insn * insn, unsigned int * data)
501 s->state &= ~data[0];
502 s->state |= (data[0] & data[1]);
504 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
505 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
513 ==============================================================================
514 analog input interrupt mode 1 & 3, 818 cards
515 one sample per interrupt version
517 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
519 struct comedi_device *dev = d;
520 struct comedi_subdevice *s = dev->subdevices + 0;
522 int timeout = 50; /* wait max 50us */
525 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
529 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
530 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
531 pcl818_ai_cancel(dev, s);
532 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
533 comedi_event(dev, s);
537 low = inb(dev->iobase + PCL818_AD_LO);
538 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
539 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
541 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
543 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
545 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
546 pcl818_ai_cancel(dev, s);
547 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
548 comedi_event(dev, s);
551 if (s->async->cur_chan == 0) {
552 /* rt_printk("E"); */
553 devpriv->ai_act_scan--;
556 if (!devpriv->neverending_ai) {
557 if (devpriv->ai_act_scan == 0) { /* all data sampled */
558 pcl818_ai_cancel(dev, s);
559 s->async->events |= COMEDI_CB_EOA;
562 comedi_event(dev, s);
567 ==============================================================================
568 analog input dma mode 1 & 3, 818 cards
570 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
572 struct comedi_device *dev = d;
573 struct comedi_subdevice *s = dev->subdevices + 0;
578 disable_dma(devpriv->dma);
579 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
580 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
581 set_dma_mode(devpriv->dma, DMA_MODE_READ);
582 flags = claim_dma_lock();
583 set_dma_addr(devpriv->dma,
584 devpriv->hwdmaptr[devpriv->next_dma_buf]);
585 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
586 set_dma_count(devpriv->dma,
587 devpriv->hwdmasize[devpriv->next_dma_buf]);
589 set_dma_count(devpriv->dma, devpriv->last_dma_run);
591 release_dma_lock(flags);
592 enable_dma(devpriv->dma);
594 rt_printk("comedi: A/D mode1/3 IRQ \n");
596 devpriv->dma_runs_to_end--;
597 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
598 ptr = (short *) devpriv->dmabuf[1 - devpriv->next_dma_buf];
600 len = devpriv->hwdmasize[0] >> 1;
603 for (i = 0; i < len; i++) {
604 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
606 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
608 devpriv->act_chanlist[devpriv->
610 devpriv->act_chanlist_pos);
611 pcl818_ai_cancel(dev, s);
612 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
613 comedi_event(dev, s);
617 comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
619 devpriv->act_chanlist_pos++;
620 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
621 devpriv->ai_act_scan--;
622 devpriv->act_chanlist_pos = 0;
625 if (!devpriv->neverending_ai)
626 if (devpriv->ai_act_scan == 0) { /* all data sampled */
627 pcl818_ai_cancel(dev, s);
628 s->async->events |= COMEDI_CB_EOA;
629 comedi_event(dev, s);
630 /* printk("done int ai13 dma\n"); */
636 comedi_event(dev, s);
642 ==============================================================================
643 analog input dma mode 1 & 3 over RTC, 818 cards
645 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
647 struct comedi_device *dev = d;
648 struct comedi_subdevice *s = dev->subdevices + 0;
650 unsigned int top1, top2, i, bufptr;
652 short *dmabuf = (short *) devpriv->dmabuf[0];
655 switch (devpriv->ai_mode) {
656 case INT_TYPE_AI1_DMA_RTC:
657 case INT_TYPE_AI3_DMA_RTC:
658 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
659 mod_timer(&devpriv->rtc_irq_timer,
660 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
662 for (i = 0; i < 10; i++) {
663 top1 = get_dma_residue(devpriv->dma);
664 top2 = get_dma_residue(devpriv->dma);
671 top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
673 ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
675 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
677 return IRQ_HANDLED; /* exit=no new samples from last call */
679 i = devpriv->last_top_dma - 1;
680 i &= (devpriv->dmasamplsize - 1);
682 if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
683 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
684 /* rt_printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
685 pcl818_ai_cancel(dev, s);
686 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
687 comedi_event(dev, s);
690 /* rt_printk("r %ld ",ofs_dats); */
692 bufptr = devpriv->last_top_dma;
694 for (i = 0; i < ofs_dats; i++) {
695 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
697 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
698 (dmabuf[bufptr] & 0xf),
699 devpriv->act_chanlist[devpriv->
701 pcl818_ai_cancel(dev, s);
703 COMEDI_CB_EOA | COMEDI_CB_ERROR;
704 comedi_event(dev, s);
708 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
709 bufptr &= (devpriv->dmasamplsize - 1);
711 if (s->async->cur_chan == 0) {
712 devpriv->ai_act_scan--;
715 if (!devpriv->neverending_ai)
716 if (devpriv->ai_act_scan == 0) { /* all data sampled */
717 pcl818_ai_cancel(dev, s);
718 s->async->events |= COMEDI_CB_EOA;
719 comedi_event(dev, s);
720 /* printk("done int ai13 dma\n"); */
725 devpriv->last_top_dma = bufptr;
727 bufptr &= (devpriv->dmasamplsize - 1);
728 dmabuf[bufptr] = MAGIC_DMA_WORD;
729 comedi_event(dev, s);
740 ==============================================================================
741 analog input interrupt mode 1 & 3, 818HD/HG cards
743 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
745 struct comedi_device *dev = d;
746 struct comedi_subdevice *s = dev->subdevices + 0;
749 outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
751 lo = inb(dev->iobase + PCL818_FI_STATUS);
754 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
755 pcl818_ai_cancel(dev, s);
756 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
757 comedi_event(dev, s);
762 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
763 pcl818_ai_cancel(dev, s);
764 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
765 comedi_event(dev, s);
775 for (i = 0; i < len; i++) {
776 lo = inb(dev->iobase + PCL818_FI_DATALO);
777 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
779 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
781 devpriv->act_chanlist[devpriv->
783 pcl818_ai_cancel(dev, s);
784 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
785 comedi_event(dev, s);
789 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
791 if (s->async->cur_chan == 0) {
792 devpriv->ai_act_scan--;
795 if (!devpriv->neverending_ai)
796 if (devpriv->ai_act_scan == 0) { /* all data sampled */
797 pcl818_ai_cancel(dev, s);
798 s->async->events |= COMEDI_CB_EOA;
799 comedi_event(dev, s);
805 comedi_event(dev, s);
810 ==============================================================================
813 static irqreturn_t interrupt_pcl818(int irq, void *d)
815 struct comedi_device *dev = d;
817 if (!dev->attached) {
818 comedi_error(dev, "premature interrupt");
821 /* rt_printk("I\n"); */
823 switch (devpriv->ai_mode) {
824 case INT_TYPE_AI1_DMA:
825 case INT_TYPE_AI3_DMA:
826 return interrupt_pcl818_ai_mode13_dma(irq, d);
827 case INT_TYPE_AI1_INT:
828 case INT_TYPE_AI3_INT:
829 return interrupt_pcl818_ai_mode13_int(irq, d);
830 case INT_TYPE_AI1_FIFO:
831 case INT_TYPE_AI3_FIFO:
832 return interrupt_pcl818_ai_mode13_fifo(irq, d);
833 #ifdef PCL818_MODE13_AO
834 case INT_TYPE_AO1_INT:
835 case INT_TYPE_AO3_INT:
836 return interrupt_pcl818_ao_mode13_int(irq, d);
842 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
844 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
845 || (!devpriv->ai_mode)) {
846 if (devpriv->irq_was_now_closed) {
847 if (devpriv->neverending_ai &&
848 (devpriv->ai_mode == INT_TYPE_AI1_DMA
849 || devpriv->ai_mode ==
851 /* we had neverending ai but ai_cancel() has been called
852 the cleanup from ai_cancel() has been delayed until know
853 because the card doesn't seem to like being reprogrammed
854 while a DMA transfer is in progress
856 struct comedi_subdevice *s = dev->subdevices + 0;
857 devpriv->ai_mode = devpriv->irq_was_now_closed;
858 devpriv->irq_was_now_closed = 0;
859 devpriv->neverending_ai = 0;
860 pcl818_ai_cancel(dev, s);
862 devpriv->irq_was_now_closed = 0;
865 comedi_error(dev, "bad IRQ!");
869 comedi_error(dev, "IRQ from unknow source!");
874 ==============================================================================
875 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
877 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device * dev,
878 struct comedi_subdevice * s)
883 rt_printk("mode13dma_int, mode: %d\n", mode);
884 disable_dma(devpriv->dma); /* disable dma */
885 bytes = devpriv->hwdmasize[0];
886 if (!devpriv->neverending_ai) {
887 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
888 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
889 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
890 devpriv->dma_runs_to_end--;
891 if (devpriv->dma_runs_to_end >= 0)
892 bytes = devpriv->hwdmasize[0];
895 devpriv->next_dma_buf = 0;
896 set_dma_mode(devpriv->dma, DMA_MODE_READ);
897 flags = claim_dma_lock();
898 clear_dma_ff(devpriv->dma);
899 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
900 set_dma_count(devpriv->dma, bytes);
901 release_dma_lock(flags);
902 enable_dma(devpriv->dma);
905 devpriv->ai_mode = INT_TYPE_AI1_DMA;
906 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
908 devpriv->ai_mode = INT_TYPE_AI3_DMA;
909 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
915 ==============================================================================
916 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
918 static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device * dev,
919 struct comedi_subdevice * s)
924 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
925 flags = claim_dma_lock();
926 clear_dma_ff(devpriv->dma);
927 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
928 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
929 release_dma_lock(flags);
930 enable_dma(devpriv->dma);
931 devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
932 pole = (short *) devpriv->dmabuf[0];
933 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
934 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
936 devpriv->rtc_freq = rtc_setfreq_irq(2048);
937 devpriv->rtc_irq_timer.expires =
938 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
939 devpriv->rtc_irq_timer.data = (unsigned long)dev;
940 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
942 add_timer(&devpriv->rtc_irq_timer);
946 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
947 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
949 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
950 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
956 ==============================================================================
957 ANALOG INPUT MODE 1 or 3, 818 cards
959 static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev,
960 struct comedi_subdevice * s)
962 struct comedi_cmd *cmd = &s->async->cmd;
963 int divisor1, divisor2;
966 rt_printk("pcl818_ai_cmd_mode()\n");
967 if ((!dev->irq) && (!devpriv->dma_rtc)) {
968 comedi_error(dev, "IRQ not defined!");
972 if (devpriv->irq_blocked)
975 start_pacer(dev, -1, 0, 0); /* stop pacer */
977 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
981 setup_channel_list(dev, s, devpriv->ai_chanlist,
982 devpriv->ai_n_chan, seglen);
986 devpriv->ai_act_scan = devpriv->ai_scans;
987 devpriv->ai_act_chan = 0;
988 devpriv->irq_blocked = 1;
989 devpriv->irq_was_now_closed = 0;
990 devpriv->neverending_ai = 0;
991 devpriv->act_chanlist_pos = 0;
992 devpriv->dma_runs_to_end = 0;
994 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
995 devpriv->neverending_ai = 1; /* well, user want neverending */
998 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
999 &divisor2, &cmd->convert_arg, TRIG_ROUND_NEAREST);
1000 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
1004 if (divisor2 == 1) {
1010 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1012 switch (devpriv->dma) {
1015 if (devpriv->dma_rtc == 0) {
1016 pcl818_ai_mode13dma_int(mode, dev, s);
1020 pcl818_ai_mode13dma_rtc(mode, dev, s);
1029 if (!devpriv->usefifo) {
1031 /* rt_printk("IRQ\n"); */
1033 devpriv->ai_mode = INT_TYPE_AI1_INT;
1035 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
1037 devpriv->ai_mode = INT_TYPE_AI3_INT;
1039 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL);
1044 outb(1, dev->iobase + PCL818_FI_ENABLE);
1046 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1048 outb(0x03, dev->iobase + PCL818_CONTROL);
1050 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1051 outb(0x02, dev->iobase + PCL818_CONTROL);
1056 start_pacer(dev, mode, divisor1, divisor2);
1059 switch (devpriv->ai_mode) {
1060 case INT_TYPE_AI1_DMA_RTC:
1061 case INT_TYPE_AI3_DMA_RTC:
1062 set_rtc_irq_bit(1); /* start RTC */
1066 rt_printk("pcl818_ai_cmd_mode() end\n");
1072 ==============================================================================
1073 ANALOG OUTPUT MODE 1 or 3, 818 cards
1075 #ifdef PCL818_MODE13_AO
1076 static int pcl818_ao_mode13(int mode, struct comedi_device * dev, struct comedi_subdevice * s,
1079 int divisor1, divisor2;
1082 comedi_error(dev, "IRQ not defined!");
1086 if (devpriv->irq_blocked)
1089 start_pacer(dev, -1, 0, 0); /* stop pacer */
1091 devpriv->int13_act_scan = it->n;
1092 devpriv->int13_act_chan = 0;
1093 devpriv->irq_blocked = 1;
1094 devpriv->irq_was_now_closed = 0;
1095 devpriv->neverending_ai = 0;
1096 devpriv->act_chanlist_pos = 0;
1099 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1100 &divisor2, &it->trigvar, TRIG_ROUND_NEAREST);
1101 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1105 if (divisor2 == 1) {
1111 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1113 devpriv->int818_mode = INT_TYPE_AO1_INT;
1114 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1116 devpriv->int818_mode = INT_TYPE_AO3_INT;
1117 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1120 start_pacer(dev, mode, divisor1, divisor2);
1126 ==============================================================================
1127 ANALOG OUTPUT MODE 1, 818 cards
1129 static int pcl818_ao_mode1(struct comedi_device * dev, struct comedi_subdevice * s,
1132 return pcl818_ao_mode13(1, dev, s, it);
1136 ==============================================================================
1137 ANALOG OUTPUT MODE 3, 818 cards
1139 static int pcl818_ao_mode3(struct comedi_device * dev, struct comedi_subdevice * s,
1142 return pcl818_ao_mode13(3, dev, s, it);
1148 ==============================================================================
1149 Start/stop pacer onboard pacer
1151 static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
1152 unsigned int divisor2)
1154 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1155 outb(0x74, dev->iobase + PCL818_CTRCTL);
1159 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1160 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1161 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1162 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1167 ==============================================================================
1168 Check if channel list from user is builded correctly
1169 If it's ok, then program scan/gain logic
1171 static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
1172 unsigned int *chanlist, unsigned int n_chan)
1174 unsigned int chansegment[16];
1175 unsigned int i, nowmustbechan, seglen, segpos;
1177 /* correct channel and range number check itself comedi/range.c */
1179 comedi_error(dev, "range/channel list is empty!");
1184 /* first channel is everytime ok */
1185 chansegment[0] = chanlist[0];
1186 /* build part of chanlist */
1187 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1189 /* rt_printk("%d. %d * %d\n",i,
1190 * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
1192 /* we detect loop, this must by finish */
1194 if (chanlist[0] == chanlist[i])
1197 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1198 if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */
1200 ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1201 dev->minor, i, CR_CHAN(chanlist[i]),
1202 nowmustbechan, CR_CHAN(chanlist[0]));
1205 /* well, this is next correct channel in list */
1206 chansegment[i] = chanlist[i];
1209 /* check whole chanlist */
1210 for (i = 0, segpos = 0; i < n_chan; i++) {
1211 /* rt_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])); */
1212 if (chanlist[i] != chansegment[i % seglen]) {
1214 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1215 dev->minor, i, CR_CHAN(chansegment[i]),
1216 CR_RANGE(chansegment[i]),
1217 CR_AREF(chansegment[i]),
1218 CR_CHAN(chanlist[i % seglen]),
1219 CR_RANGE(chanlist[i % seglen]),
1220 CR_AREF(chansegment[i % seglen]));
1221 return 0; /* chan/gain list is strange */
1227 rt_printk("check_channel_list: seglen %d\n", seglen);
1231 static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
1232 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen)
1236 devpriv->act_chanlist_len = seglen;
1237 devpriv->act_chanlist_pos = 0;
1239 for (i = 0; i < seglen; i++) { /* store range list to card */
1240 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1241 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1242 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1247 /* select channel interval to scan */
1248 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1249 1] << 4), dev->iobase + PCL818_MUX);
1253 ==============================================================================
1254 Check if board is switched to SE (1) or DIFF(0) mode
1256 static int check_single_ended(unsigned int port)
1258 if (inb(port + PCL818_STATUS) & 0x20) {
1266 ==============================================================================
1268 static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
1269 struct comedi_cmd * cmd)
1272 int tmp, divisor1, divisor2;
1274 /* step 1: make sure trigger sources are trivially valid */
1276 tmp = cmd->start_src;
1277 cmd->start_src &= TRIG_NOW;
1278 if (!cmd->start_src || tmp != cmd->start_src)
1281 tmp = cmd->scan_begin_src;
1282 cmd->scan_begin_src &= TRIG_FOLLOW;
1283 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1286 tmp = cmd->convert_src;
1287 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1288 if (!cmd->convert_src || tmp != cmd->convert_src)
1291 tmp = cmd->scan_end_src;
1292 cmd->scan_end_src &= TRIG_COUNT;
1293 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1296 tmp = cmd->stop_src;
1297 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1298 if (!cmd->stop_src || tmp != cmd->stop_src)
1305 /* step 2: make sure trigger sources are unique and mutually compatible */
1307 if (cmd->start_src != TRIG_NOW) {
1308 cmd->start_src = TRIG_NOW;
1311 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1312 cmd->scan_begin_src = TRIG_FOLLOW;
1315 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1318 if (cmd->scan_end_src != TRIG_COUNT) {
1319 cmd->scan_end_src = TRIG_COUNT;
1323 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1330 /* step 3: make sure arguments are trivially compatible */
1332 if (cmd->start_arg != 0) {
1337 if (cmd->scan_begin_arg != 0) {
1338 cmd->scan_begin_arg = 0;
1342 if (cmd->convert_src == TRIG_TIMER) {
1343 if (cmd->convert_arg < this_board->ns_min) {
1344 cmd->convert_arg = this_board->ns_min;
1347 } else { /* TRIG_EXT */
1348 if (cmd->convert_arg != 0) {
1349 cmd->convert_arg = 0;
1354 if (!cmd->chanlist_len) {
1355 cmd->chanlist_len = 1;
1358 if (cmd->chanlist_len > s->n_chan) {
1359 cmd->chanlist_len = s->n_chan;
1362 if (cmd->scan_end_arg != cmd->chanlist_len) {
1363 cmd->scan_end_arg = cmd->chanlist_len;
1366 if (cmd->stop_src == TRIG_COUNT) {
1367 if (!cmd->stop_arg) {
1371 } else { /* TRIG_NONE */
1372 if (cmd->stop_arg != 0) {
1382 /* step 4: fix up any arguments */
1384 if (cmd->convert_src == TRIG_TIMER) {
1385 tmp = cmd->convert_arg;
1386 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1387 &divisor2, &cmd->convert_arg,
1388 cmd->flags & TRIG_ROUND_MASK);
1389 if (cmd->convert_arg < this_board->ns_min)
1390 cmd->convert_arg = this_board->ns_min;
1391 if (tmp != cmd->convert_arg)
1399 /* step 5: complain about special chanlist considerations */
1401 if (cmd->chanlist) {
1402 if (!check_channel_list(dev, s, cmd->chanlist,
1404 return 5; /* incorrect channels list */
1411 ==============================================================================
1413 static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
1415 struct comedi_cmd *cmd = &s->async->cmd;
1418 rt_printk("pcl818_ai_cmd()\n");
1419 devpriv->ai_n_chan = cmd->chanlist_len;
1420 devpriv->ai_chanlist = cmd->chanlist;
1421 devpriv->ai_flags = cmd->flags;
1422 devpriv->ai_data_len = s->async->prealloc_bufsz;
1423 devpriv->ai_data = s->async->prealloc_buf;
1424 devpriv->ai_timer1 = 0;
1425 devpriv->ai_timer2 = 0;
1427 if (cmd->stop_src == TRIG_COUNT) {
1428 devpriv->ai_scans = cmd->stop_arg;
1430 devpriv->ai_scans = 0;
1433 if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
1434 if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
1435 devpriv->ai_timer1 = cmd->convert_arg;
1436 retval = pcl818_ai_cmd_mode(1, dev, s);
1437 rt_printk("pcl818_ai_cmd() end\n");
1440 if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
1441 return pcl818_ai_cmd_mode(3, dev, s);
1449 ==============================================================================
1450 cancel any mode 1-4 AI
1452 static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
1454 if (devpriv->irq_blocked > 0) {
1455 rt_printk("pcl818_ai_cancel()\n");
1456 devpriv->irq_was_now_closed = devpriv->ai_mode;
1457 devpriv->ai_mode = 0;
1459 switch (devpriv->irq_was_now_closed) {
1461 case INT_TYPE_AI1_DMA_RTC:
1462 case INT_TYPE_AI3_DMA_RTC:
1463 set_rtc_irq_bit(0); /* stop RTC */
1464 del_timer(&devpriv->rtc_irq_timer);
1466 case INT_TYPE_AI1_DMA:
1467 case INT_TYPE_AI3_DMA:
1468 if (devpriv->neverending_ai) {
1469 /* wait for running dma transfer to end, do cleanup in interrupt */
1472 disable_dma(devpriv->dma);
1473 case INT_TYPE_AI1_INT:
1474 case INT_TYPE_AI3_INT:
1475 case INT_TYPE_AI1_FIFO:
1476 case INT_TYPE_AI3_FIFO:
1477 #ifdef PCL818_MODE13_AO
1478 case INT_TYPE_AO1_INT:
1479 case INT_TYPE_AO3_INT:
1481 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1483 start_pacer(dev, -1, 0, 0);
1484 outb(0, dev->iobase + PCL818_AD_LO);
1485 inb(dev->iobase + PCL818_AD_LO);
1486 inb(dev->iobase + PCL818_AD_HI);
1487 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1488 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1489 if (devpriv->usefifo) { /* FIFO shutdown */
1490 outb(0, dev->iobase + PCL818_FI_INTCLR);
1491 outb(0, dev->iobase + PCL818_FI_FLUSH);
1492 outb(0, dev->iobase + PCL818_FI_ENABLE);
1494 devpriv->irq_blocked = 0;
1495 devpriv->last_int_sub = s;
1496 devpriv->neverending_ai = 0;
1502 rt_printk("pcl818_ai_cancel() end\n");
1507 ==============================================================================
1510 static int pcl818_check(unsigned long iobase)
1512 outb(0x00, iobase + PCL818_MUX);
1514 if (inb(iobase + PCL818_MUX) != 0x00)
1515 return 1; /* there isn't card */
1516 outb(0x55, iobase + PCL818_MUX);
1518 if (inb(iobase + PCL818_MUX) != 0x55)
1519 return 1; /* there isn't card */
1520 outb(0x00, iobase + PCL818_MUX);
1522 outb(0x18, iobase + PCL818_CONTROL);
1524 if (inb(iobase + PCL818_CONTROL) != 0x18)
1525 return 1; /* there isn't card */
1526 return 0; /* ok, card exist */
1530 ==============================================================================
1531 reset whole PCL-818 cards
1533 static void pcl818_reset(struct comedi_device * dev)
1535 if (devpriv->usefifo) { /* FIFO shutdown */
1536 outb(0, dev->iobase + PCL818_FI_INTCLR);
1537 outb(0, dev->iobase + PCL818_FI_FLUSH);
1538 outb(0, dev->iobase + PCL818_FI_ENABLE);
1540 outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
1541 outb(0, dev->iobase + PCL818_DA_HI);
1543 outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
1544 outb(0, dev->iobase + PCL818_DO_LO);
1546 outb(0, dev->iobase + PCL818_CONTROL);
1547 outb(0, dev->iobase + PCL818_CNTENABLE);
1548 outb(0, dev->iobase + PCL818_MUX);
1549 outb(0, dev->iobase + PCL818_CLRINT);
1550 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1551 outb(0x70, dev->iobase + PCL818_CTRCTL);
1552 outb(0x30, dev->iobase + PCL818_CTRCTL);
1553 if (this_board->is_818) {
1554 outb(0, dev->iobase + PCL818_RANGE);
1556 outb(0, dev->iobase + PCL718_DA2_LO);
1557 outb(0, dev->iobase + PCL718_DA2_HI);
1563 ==============================================================================
1564 Enable(1)/disable(0) periodic interrupts from RTC
1566 static int set_rtc_irq_bit(unsigned char bit)
1569 unsigned long flags;
1573 if (RTC_timer_lock > 1)
1577 if (RTC_timer_lock < 0)
1579 if (RTC_timer_lock > 0)
1585 val = CMOS_READ(RTC_CONTROL);
1591 CMOS_WRITE(val, RTC_CONTROL);
1592 CMOS_READ(RTC_INTR_FLAGS);
1593 restore_flags(flags);
1598 ==============================================================================
1599 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1601 static void rtc_dropped_irq(unsigned long data)
1603 struct comedi_device *dev = (void *)data;
1604 unsigned long flags, tmp;
1606 switch (devpriv->int818_mode) {
1607 case INT_TYPE_AI1_DMA_RTC:
1608 case INT_TYPE_AI3_DMA_RTC:
1609 mod_timer(&devpriv->rtc_irq_timer,
1610 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1613 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1614 restore_flags(flags);
1620 ==============================================================================
1621 Set frequency of interrupts from RTC
1623 static int rtc_setfreq_irq(int freq)
1628 unsigned long flags;
1635 while (freq > (1 << tmp))
1638 rtc_freq = 1 << tmp;
1642 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1644 CMOS_WRITE(val, RTC_FREQ_SELECT);
1645 restore_flags(flags);
1651 ==============================================================================
1652 Free any resources that we have claimed
1654 static void free_resources(struct comedi_device * dev)
1656 /* rt_printk("free_resource()\n"); */
1658 pcl818_ai_cancel(dev, devpriv->sub_ai);
1661 free_dma(devpriv->dma);
1662 if (devpriv->dmabuf[0])
1663 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1664 if (devpriv->dmabuf[1])
1665 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1667 if (devpriv->rtc_irq)
1668 comedi_free_irq(devpriv->rtc_irq, dev);
1669 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1670 if (devpriv->rtc_iobase)
1671 release_region(devpriv->rtc_iobase,
1672 devpriv->rtc_iosize);
1674 if (devpriv->dma_rtc)
1680 free_irq(dev->irq, dev);
1682 release_region(dev->iobase, devpriv->io_range);
1683 /* rt_printk("free_resource() end\n"); */
1687 ==============================================================================
1692 static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * it)
1695 unsigned long iobase;
1698 unsigned long pages;
1699 struct comedi_subdevice *s;
1701 if ((ret = alloc_private(dev, sizeof(struct pcl818_private))) < 0)
1702 return ret; /* Can't alloc mem */
1704 /* claim our I/O space */
1705 iobase = it->options[0];
1706 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1707 dev->minor, this_board->name, iobase);
1708 devpriv->io_range = this_board->io_range;
1709 if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */
1710 devpriv->io_range = PCLx1xFIFO_RANGE;
1711 devpriv->usefifo = 1;
1713 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1714 rt_printk("I/O port conflict\n");
1718 dev->iobase = iobase;
1720 if (pcl818_check(iobase)) {
1721 rt_printk(", I can't detect board. FAIL!\n");
1725 /* set up some name stuff */
1726 dev->board_name = this_board->name;
1729 if (this_board->IRQbits != 0) { /* board support IRQ */
1730 irq = it->options[1];
1731 if (irq) { /* we want to use IRQ */
1732 if (((1 << irq) & this_board->IRQbits) == 0) {
1734 (", IRQ %u is out of allowed range, DISABLING IT",
1736 irq = 0; /* Bad IRQ */
1738 if (comedi_request_irq(irq, interrupt_pcl818, 0,
1741 (", unable to allocate IRQ %u, DISABLING IT",
1743 irq = 0; /* Can't use IRQ */
1745 rt_printk(", irq=%u", irq);
1753 devpriv->irq_free = 1;
1754 } /* 1=we have allocated irq */
1756 devpriv->irq_free = 0;
1758 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1759 devpriv->ai_mode = 0; /* mode of irq */
1762 /* grab RTC for DMA operations */
1763 devpriv->dma_rtc = 0;
1764 if (it->options[2] > 0) { /* we want to use DMA */
1765 if (RTC_lock == 0) {
1766 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1770 devpriv->rtc_iobase = RTC_PORT(0);
1771 devpriv->rtc_iosize = RTC_IO_EXTENT;
1773 if (!comedi_request_irq(RTC_IRQ,
1774 interrupt_pcl818_ai_mode13_dma_rtc, 0,
1775 "pcl818 DMA (RTC)", dev)) {
1776 devpriv->dma_rtc = 1;
1777 devpriv->rtc_irq = RTC_IRQ;
1778 rt_printk(", dma_irq=%u", devpriv->rtc_irq);
1781 if (RTC_lock == 0) {
1782 if (devpriv->rtc_iobase)
1783 release_region(devpriv->rtc_iobase,
1784 devpriv->rtc_iosize);
1786 devpriv->rtc_iobase = 0;
1787 devpriv->rtc_iosize = 0;
1796 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1797 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1798 if (this_board->DMAbits != 0) { /* board support DMA */
1799 dma = it->options[2];
1801 goto no_dma; /* DMA disabled */
1802 if (((1 << dma) & this_board->DMAbits) == 0) {
1803 rt_printk(", DMA is out of allowed range, FAIL!\n");
1804 return -EINVAL; /* Bad DMA */
1806 ret = request_dma(dma, "pcl818");
1808 rt_printk(", unable to allocate DMA %u, FAIL!\n", dma);
1809 return -EBUSY; /* DMA isn't free */
1812 rt_printk(", dma=%u", dma);
1813 pages = 2; /* we need 16KB */
1814 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1815 if (!devpriv->dmabuf[0]) {
1816 rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1817 /* maybe experiment with try_to_free_pages() will help .... */
1818 return -EBUSY; /* no buffer :-( */
1820 devpriv->dmapages[0] = pages;
1821 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1822 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1823 /* rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1824 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1825 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1826 if (!devpriv->dmabuf[1]) {
1828 (", unable to allocate DMA buffer, FAIL!\n");
1831 devpriv->dmapages[1] = pages;
1832 devpriv->hwdmaptr[1] =
1833 virt_to_bus((void *)devpriv->dmabuf[1]);
1834 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1840 if ((ret = alloc_subdevices(dev, 4)) < 0)
1843 s = dev->subdevices + 0;
1844 if (!this_board->n_aichan_se) {
1845 s->type = COMEDI_SUBD_UNUSED;
1847 s->type = COMEDI_SUBD_AI;
1848 devpriv->sub_ai = s;
1849 s->subdev_flags = SDF_READABLE;
1850 if (check_single_ended(dev->iobase)) {
1851 s->n_chan = this_board->n_aichan_se;
1852 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1853 printk(", %dchans S.E. DAC", s->n_chan);
1855 s->n_chan = this_board->n_aichan_diff;
1856 s->subdev_flags |= SDF_DIFF;
1857 printk(", %dchans DIFF DAC", s->n_chan);
1859 s->maxdata = this_board->ai_maxdata;
1860 s->len_chanlist = s->n_chan;
1861 s->range_table = this_board->ai_range_type;
1862 s->cancel = pcl818_ai_cancel;
1863 s->insn_read = pcl818_ai_insn_read;
1864 if ((irq) || (devpriv->dma_rtc)) {
1865 dev->read_subdev = s;
1866 s->subdev_flags |= SDF_CMD_READ;
1867 s->do_cmdtest = ai_cmdtest;
1870 if (this_board->is_818) {
1871 if ((it->options[4] == 1) || (it->options[4] == 10))
1872 s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
1874 switch (it->options[4]) {
1876 s->range_table = &range_bipolar10;
1879 s->range_table = &range_bipolar5;
1882 s->range_table = &range_bipolar2_5;
1885 s->range_table = &range718_bipolar1;
1888 s->range_table = &range718_bipolar0_5;
1891 s->range_table = &range_unipolar10;
1894 s->range_table = &range_unipolar5;
1897 s->range_table = &range718_unipolar2;
1900 s->range_table = &range718_unipolar1;
1903 s->range_table = &range_unknown;
1909 s = dev->subdevices + 1;
1910 if (!this_board->n_aochan) {
1911 s->type = COMEDI_SUBD_UNUSED;
1913 s->type = COMEDI_SUBD_AO;
1914 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1915 s->n_chan = this_board->n_aochan;
1916 s->maxdata = this_board->ao_maxdata;
1917 s->len_chanlist = this_board->n_aochan;
1918 s->range_table = this_board->ao_range_type;
1919 s->insn_read = pcl818_ao_insn_read;
1920 s->insn_write = pcl818_ao_insn_write;
1922 #ifdef PCL818_MODE13_AO
1924 s->trig[1] = pcl818_ao_mode1;
1925 s->trig[3] = pcl818_ao_mode3;
1929 if (this_board->is_818) {
1930 if ((it->options[4] == 1) || (it->options[4] == 10))
1931 s->range_table = &range_unipolar10;
1932 if (it->options[4] == 2)
1933 s->range_table = &range_unknown;
1935 if ((it->options[5] == 1) || (it->options[5] == 10))
1936 s->range_table = &range_unipolar10;
1937 if (it->options[5] == 2)
1938 s->range_table = &range_unknown;
1942 s = dev->subdevices + 2;
1943 if (!this_board->n_dichan) {
1944 s->type = COMEDI_SUBD_UNUSED;
1946 s->type = COMEDI_SUBD_DI;
1947 s->subdev_flags = SDF_READABLE;
1948 s->n_chan = this_board->n_dichan;
1950 s->len_chanlist = this_board->n_dichan;
1951 s->range_table = &range_digital;
1952 s->insn_bits = pcl818_di_insn_bits;
1955 s = dev->subdevices + 3;
1956 if (!this_board->n_dochan) {
1957 s->type = COMEDI_SUBD_UNUSED;
1959 s->type = COMEDI_SUBD_DO;
1960 s->subdev_flags = SDF_WRITABLE;
1961 s->n_chan = this_board->n_dochan;
1963 s->len_chanlist = this_board->n_dochan;
1964 s->range_table = &range_digital;
1965 s->insn_bits = pcl818_do_insn_bits;
1968 /* select 1/10MHz oscilator */
1969 if ((it->options[3] == 0) || (it->options[3] == 10)) {
1970 devpriv->i8253_osc_base = 100;
1972 devpriv->i8253_osc_base = 1000;
1975 /* max sampling speed */
1976 devpriv->ns_min = this_board->ns_min;
1978 if (!this_board->is_818) {
1979 if ((it->options[6] == 1) || (it->options[6] == 100))
1980 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1991 ==============================================================================
1994 static int pcl818_detach(struct comedi_device * dev)
1996 /* rt_printk("comedi%d: pcl818: remove\n", dev->minor); */
1997 free_resources(dev);