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
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
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 comedi_lrange range_pcl818h_ai = { 9, {
210 static const comedi_lrange range_pcl818hg_ai = { 10, {
226 static const comedi_lrange range_pcl818l_l_ai = { 4, {
234 static const comedi_lrange range_pcl818l_h_ai = { 4, {
242 static const comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
243 static const comedi_lrange range718_bipolar0_5 = { 1, {BIP_RANGE(0.5),} };
244 static const comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
245 static const comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
247 static int pcl818_attach(comedi_device * dev, comedi_devconfig * it);
248 static int pcl818_detach(comedi_device * dev);
251 static int RTC_lock = 0; /* RTC lock */
252 static int RTC_timer_lock = 0; /* RTC int lock */
256 const char *name; // driver name
257 int n_ranges; // len of range list
258 int n_aichan_se; // num of A/D chans in single ended mode
259 int n_aichan_diff; // num of A/D chans in diferencial mode
260 unsigned int ns_min; // minimal alllowed delay between samples (in ns)
261 int n_aochan; // num of D/A chans
262 int n_dichan; // num of DI chans
263 int n_dochan; // num of DO chans
264 const comedi_lrange *ai_range_type; // default A/D rangelist
265 const comedi_lrange *ao_range_type; // default D/A rangelist
266 unsigned int io_range; // len of IO space
267 unsigned int IRQbits; // allowed interrupts
268 unsigned int DMAbits; // allowed DMA chans
269 int ai_maxdata; // maxdata for A/D
270 int ao_maxdata; // maxdata for D/A
271 unsigned char fifo; // 1=board has FIFO
275 static const boardtype boardtypes[] = {
276 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
277 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
278 0x0a, 0xfff, 0xfff, 0, 1},
279 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
280 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
281 0x0a, 0xfff, 0xfff, 0, 1},
282 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
283 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
284 0x0a, 0xfff, 0xfff, 1, 1},
285 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
286 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
287 0x0a, 0xfff, 0xfff, 1, 1},
288 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
289 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
290 0x0a, 0xfff, 0xfff, 0, 1},
291 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
292 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
293 0x0a, 0xfff, 0xfff, 0, 0},
295 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
296 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
297 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
300 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
302 static comedi_driver driver_pcl818 = {
303 driver_name:"pcl818",
305 attach:pcl818_attach,
306 detach:pcl818_detach,
307 board_name:&boardtypes[0].name,
308 num_names:n_boardtypes,
309 offset:sizeof(boardtype),
312 COMEDI_INITCLEANUP(driver_pcl818);
315 unsigned int dma; // used DMA, 0=don't use DMA
316 int dma_rtc; // 1=RTC used with DMA, 0=no RTC alloc
317 unsigned int io_range;
319 unsigned long rtc_iobase; // RTC port region
320 unsigned int rtc_iosize;
321 unsigned int rtc_irq;
322 struct timer_list rtc_irq_timer; // timer for RTC sanity check
323 unsigned long rtc_freq; // RTC int freq
324 int rtc_irq_blocked; // 1=we now do AI with DMA&RTC
326 unsigned long dmabuf[2]; // pointers to begin of DMA buffers
327 unsigned int dmapages[2]; // len of DMA buffers in PAGE_SIZEs
328 unsigned int hwdmaptr[2]; // hardware address of DMA buffers
329 unsigned int hwdmasize[2]; // len of DMA buffers in Bytes
330 unsigned int dmasamplsize; // size in samples hwdmasize[0]/2
331 unsigned int last_top_dma; // DMA pointer in last RTC int
332 int next_dma_buf; // which DMA buffer will be used next round
333 long dma_runs_to_end; // how many we must permorm DMA transfer to end of record
334 unsigned long last_dma_run; // how many bytes we must transfer on last DMA page
335 unsigned char neverending_ai; // if=1, then we do neverending record (you must use cancel())
336 unsigned int ns_min; // manimal alllowed delay between samples (in us) for actual card
337 int i8253_osc_base; // 1/frequency of on board oscilator in ns
338 int irq_free; // 1=have allocated IRQ
339 int irq_blocked; // 1=IRQ now uses any subdev
340 int irq_was_now_closed; // when IRQ finish, there's stored int818_mode for last interrupt
341 int ai_mode; // who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma
342 comedi_subdevice *last_int_sub; // ptr to subdevice which now finish
343 int ai_act_scan; // how many scans we finished
344 int ai_act_chan; // actual position in actual scan
345 unsigned int act_chanlist[16]; // MUX setting for actual AI operations
346 unsigned int act_chanlist_len; // how long is actual MUX list
347 unsigned int act_chanlist_pos; // actual position in MUX list
348 unsigned int ai_scans; // len of scanlist
349 unsigned int ai_n_chan; // how many channels is measured
350 unsigned int *ai_chanlist; // actaul chanlist
351 unsigned int ai_flags; // flaglist
352 unsigned int ai_data_len; // len of data buffer
353 short *ai_data; // data buffer
354 unsigned int ai_timer1; // timers
355 unsigned int ai_timer2;
356 comedi_subdevice *sub_ai; // ptr to AI subdevice
357 unsigned char usefifo; // 1=use fifo
358 unsigned int ao_readback[2];
361 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // used for gain list programming
362 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
365 #define devpriv ((pcl818_private *)dev->private)
366 #define this_board ((const boardtype *)dev->board_ptr)
369 ==============================================================================
371 static void setup_channel_list(comedi_device * dev, comedi_subdevice * s,
372 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen);
373 static int check_channel_list(comedi_device * dev, comedi_subdevice * s,
374 unsigned int *chanlist, unsigned int n_chan);
376 static int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s);
377 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1,
378 unsigned int divisor2);
381 static int set_rtc_irq_bit(unsigned char bit);
382 static void rtc_dropped_irq(unsigned long data);
383 static int rtc_setfreq_irq(int freq);
387 ==============================================================================
388 ANALOG INPUT MODE0, 818 cards, slow version
390 static int pcl818_ai_insn_read(comedi_device * dev, comedi_subdevice * s,
391 comedi_insn * insn, unsigned int * data)
396 /* software trigger, DMA and INT off */
397 outb(0, dev->iobase + PCL818_CONTROL);
400 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
403 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
405 for (n = 0; n < insn->n; n++) {
407 /* clear INT (conversion end) flag */
408 outb(0, dev->iobase + PCL818_CLRINT);
410 /* start conversion */
411 outb(0, dev->iobase + PCL818_AD_LO);
415 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
419 comedi_error(dev, "A/D insn timeout");
420 /* clear INT (conversion end) flag */
421 outb(0, dev->iobase + PCL818_CLRINT);
425 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
426 (inb(dev->iobase + PCL818_AD_LO) >> 4));
433 ==============================================================================
434 ANALOG OUTPUT MODE0, 818 cards
435 only one sample per call is supported
437 static int pcl818_ao_insn_read(comedi_device * dev, comedi_subdevice * s,
438 comedi_insn * insn, unsigned int * data)
441 int chan = CR_CHAN(insn->chanspec);
443 for (n = 0; n < insn->n; n++) {
444 data[n] = devpriv->ao_readback[chan];
450 static int pcl818_ao_insn_write(comedi_device * dev, comedi_subdevice * s,
451 comedi_insn * insn, unsigned int * data)
454 int chan = CR_CHAN(insn->chanspec);
456 for (n = 0; n < insn->n; n++) {
457 devpriv->ao_readback[chan] = data[n];
458 outb((data[n] & 0x000f) << 4, dev->iobase +
459 (chan) ? PCL718_DA2_LO : PCL818_DA_LO);
460 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
461 (chan) ? PCL718_DA2_HI : PCL818_DA_HI);
468 ==============================================================================
469 DIGITAL INPUT MODE0, 818 cards
471 only one sample per call is supported
473 static int pcl818_di_insn_bits(comedi_device * dev, comedi_subdevice * s,
474 comedi_insn * insn, unsigned int * data)
479 data[1] = inb(dev->iobase + PCL818_DI_LO) |
480 (inb(dev->iobase + PCL818_DI_HI) << 8);
486 ==============================================================================
487 DIGITAL OUTPUT MODE0, 818 cards
489 only one sample per call is supported
491 static int pcl818_do_insn_bits(comedi_device * dev, comedi_subdevice * s,
492 comedi_insn * insn, unsigned int * data)
497 s->state &= ~data[0];
498 s->state |= (data[0] & data[1]);
500 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
501 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
509 ==============================================================================
510 analog input interrupt mode 1 & 3, 818 cards
511 one sample per interrupt version
513 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
515 comedi_device *dev = d;
516 comedi_subdevice *s = dev->subdevices + 0;
518 int timeout = 50; /* wait max 50us */
521 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
525 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
526 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
527 pcl818_ai_cancel(dev, s);
528 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
529 comedi_event(dev, s);
533 low = inb(dev->iobase + PCL818_AD_LO);
534 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); // get one sample
535 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
537 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
539 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
541 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
542 pcl818_ai_cancel(dev, s);
543 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
544 comedi_event(dev, s);
547 if (s->async->cur_chan == 0) {
549 devpriv->ai_act_scan--;
552 if (!devpriv->neverending_ai) {
553 if (devpriv->ai_act_scan == 0) { /* all data sampled */
554 pcl818_ai_cancel(dev, s);
555 s->async->events |= COMEDI_CB_EOA;
558 comedi_event(dev, s);
563 ==============================================================================
564 analog input dma mode 1 & 3, 818 cards
566 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
568 comedi_device *dev = d;
569 comedi_subdevice *s = dev->subdevices + 0;
574 disable_dma(devpriv->dma);
575 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
576 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { // switch dma bufs
577 set_dma_mode(devpriv->dma, DMA_MODE_READ);
578 flags = claim_dma_lock();
579 set_dma_addr(devpriv->dma,
580 devpriv->hwdmaptr[devpriv->next_dma_buf]);
581 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
582 set_dma_count(devpriv->dma,
583 devpriv->hwdmasize[devpriv->next_dma_buf]);
585 set_dma_count(devpriv->dma, devpriv->last_dma_run);
587 release_dma_lock(flags);
588 enable_dma(devpriv->dma);
590 rt_printk("comedi: A/D mode1/3 IRQ \n");
592 devpriv->dma_runs_to_end--;
593 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
594 ptr = (short *) devpriv->dmabuf[1 - devpriv->next_dma_buf];
596 len = devpriv->hwdmasize[0] >> 1;
599 for (i = 0; i < len; i++) {
600 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
602 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
604 devpriv->act_chanlist[devpriv->
606 devpriv->act_chanlist_pos);
607 pcl818_ai_cancel(dev, s);
608 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
609 comedi_event(dev, s);
613 comedi_buf_put(s->async, ptr[bufptr++] >> 4); // get one sample
615 devpriv->act_chanlist_pos++;
616 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
617 devpriv->ai_act_scan--;
618 devpriv->act_chanlist_pos = 0;
621 if (!devpriv->neverending_ai)
622 if (devpriv->ai_act_scan == 0) { /* all data sampled */
623 pcl818_ai_cancel(dev, s);
624 s->async->events |= COMEDI_CB_EOA;
625 comedi_event(dev, s);
626 // printk("done int ai13 dma\n");
632 comedi_event(dev, s);
638 ==============================================================================
639 analog input dma mode 1 & 3 over RTC, 818 cards
641 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
643 comedi_device *dev = d;
644 comedi_subdevice *s = dev->subdevices + 0;
646 unsigned int top1, top2, i, bufptr;
648 short *dmabuf = (short *) devpriv->dmabuf[0];
651 switch (devpriv->ai_mode) {
652 case INT_TYPE_AI1_DMA_RTC:
653 case INT_TYPE_AI3_DMA_RTC:
654 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
655 mod_timer(&devpriv->rtc_irq_timer,
656 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
658 for (i = 0; i < 10; i++) {
659 top1 = get_dma_residue(devpriv->dma);
660 top2 = get_dma_residue(devpriv->dma);
667 top1 = devpriv->hwdmasize[0] - top1; // where is now DMA in buffer
669 ofs_dats = top1 - devpriv->last_top_dma; // new samples from last call
671 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
673 return IRQ_HANDLED; // exit=no new samples from last call
675 i = devpriv->last_top_dma - 1;
676 i &= (devpriv->dmasamplsize - 1);
678 if (dmabuf[i] != MAGIC_DMA_WORD) { // DMA overflow!
679 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
680 //rt_printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize);
681 pcl818_ai_cancel(dev, s);
682 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
683 comedi_event(dev, s);
686 //rt_printk("r %ld ",ofs_dats);
688 bufptr = devpriv->last_top_dma;
690 for (i = 0; i < ofs_dats; i++) {
691 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
693 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
694 (dmabuf[bufptr] & 0xf),
695 devpriv->act_chanlist[devpriv->
697 pcl818_ai_cancel(dev, s);
699 COMEDI_CB_EOA | COMEDI_CB_ERROR;
700 comedi_event(dev, s);
704 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); // get one sample
705 bufptr &= (devpriv->dmasamplsize - 1);
707 if (s->async->cur_chan == 0) {
708 devpriv->ai_act_scan--;
711 if (!devpriv->neverending_ai)
712 if (devpriv->ai_act_scan == 0) { /* all data sampled */
713 pcl818_ai_cancel(dev, s);
714 s->async->events |= COMEDI_CB_EOA;
715 comedi_event(dev, s);
716 //printk("done int ai13 dma\n");
721 devpriv->last_top_dma = bufptr;
723 bufptr &= (devpriv->dmasamplsize - 1);
724 dmabuf[bufptr] = MAGIC_DMA_WORD;
725 comedi_event(dev, s);
736 ==============================================================================
737 analog input interrupt mode 1 & 3, 818HD/HG cards
739 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
741 comedi_device *dev = d;
742 comedi_subdevice *s = dev->subdevices + 0;
745 outb(0, dev->iobase + PCL818_FI_INTCLR); // clear fifo int request
747 lo = inb(dev->iobase + PCL818_FI_STATUS);
750 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
751 pcl818_ai_cancel(dev, s);
752 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
753 comedi_event(dev, s);
758 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
759 pcl818_ai_cancel(dev, s);
760 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
761 comedi_event(dev, s);
771 for (i = 0; i < len; i++) {
772 lo = inb(dev->iobase + PCL818_FI_DATALO);
773 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
775 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
777 devpriv->act_chanlist[devpriv->
779 pcl818_ai_cancel(dev, s);
780 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
781 comedi_event(dev, s);
785 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); // get one sample
787 if (s->async->cur_chan == 0) {
788 devpriv->ai_act_scan--;
791 if (!devpriv->neverending_ai)
792 if (devpriv->ai_act_scan == 0) { /* all data sampled */
793 pcl818_ai_cancel(dev, s);
794 s->async->events |= COMEDI_CB_EOA;
795 comedi_event(dev, s);
801 comedi_event(dev, s);
806 ==============================================================================
809 static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG)
811 comedi_device *dev = d;
813 if (!dev->attached) {
814 comedi_error(dev, "premature interrupt");
819 switch (devpriv->ai_mode) {
820 case INT_TYPE_AI1_DMA:
821 case INT_TYPE_AI3_DMA:
822 return interrupt_pcl818_ai_mode13_dma(irq, d);
823 case INT_TYPE_AI1_INT:
824 case INT_TYPE_AI3_INT:
825 return interrupt_pcl818_ai_mode13_int(irq, d);
826 case INT_TYPE_AI1_FIFO:
827 case INT_TYPE_AI3_FIFO:
828 return interrupt_pcl818_ai_mode13_fifo(irq, d);
829 #ifdef PCL818_MODE13_AO
830 case INT_TYPE_AO1_INT:
831 case INT_TYPE_AO3_INT:
832 return interrupt_pcl818_ao_mode13_int(irq, d);
838 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
840 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
841 || (!devpriv->ai_mode)) {
842 if (devpriv->irq_was_now_closed) {
843 if (devpriv->neverending_ai &&
844 (devpriv->ai_mode == INT_TYPE_AI1_DMA
845 || devpriv->ai_mode ==
847 /* we had neverending ai but ai_cancel() has been called
848 the cleanup from ai_cancel() has been delayed until know
849 because the card doesn't seem to like being reprogrammed
850 while a DMA transfer is in progress
852 comedi_subdevice *s = dev->subdevices + 0;
853 devpriv->ai_mode = devpriv->irq_was_now_closed;
854 devpriv->irq_was_now_closed = 0;
855 devpriv->neverending_ai = 0;
856 pcl818_ai_cancel(dev, s);
858 devpriv->irq_was_now_closed = 0;
861 comedi_error(dev, "bad IRQ!");
865 comedi_error(dev, "IRQ from unknow source!");
870 ==============================================================================
871 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
873 static void pcl818_ai_mode13dma_int(int mode, comedi_device * dev,
874 comedi_subdevice * s)
879 rt_printk("mode13dma_int, mode: %d\n", mode);
880 disable_dma(devpriv->dma); // disable dma
881 bytes = devpriv->hwdmasize[0];
882 if (!devpriv->neverending_ai) {
883 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); // how many
884 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; // how many DMA pages we must fiil
885 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; //on last dma transfer must be moved
886 devpriv->dma_runs_to_end--;
887 if (devpriv->dma_runs_to_end >= 0)
888 bytes = devpriv->hwdmasize[0];
891 devpriv->next_dma_buf = 0;
892 set_dma_mode(devpriv->dma, DMA_MODE_READ);
893 flags = claim_dma_lock();
894 clear_dma_ff(devpriv->dma);
895 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
896 set_dma_count(devpriv->dma, bytes);
897 release_dma_lock(flags);
898 enable_dma(devpriv->dma);
901 devpriv->ai_mode = INT_TYPE_AI1_DMA;
902 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
904 devpriv->ai_mode = INT_TYPE_AI3_DMA;
905 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
911 ==============================================================================
912 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
914 static void pcl818_ai_mode13dma_rtc(int mode, comedi_device * dev,
915 comedi_subdevice * s)
920 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
921 flags = claim_dma_lock();
922 clear_dma_ff(devpriv->dma);
923 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
924 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
925 release_dma_lock(flags);
926 enable_dma(devpriv->dma);
927 devpriv->last_top_dma = 0; //devpriv->hwdmasize[0];
928 pole = (short *) devpriv->dmabuf[0];
929 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
930 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
932 devpriv->rtc_freq = rtc_setfreq_irq(2048);
933 devpriv->rtc_irq_timer.expires =
934 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
935 devpriv->rtc_irq_timer.data = (unsigned long)dev;
936 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
938 add_timer(&devpriv->rtc_irq_timer);
942 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
943 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
945 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
946 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
952 ==============================================================================
953 ANALOG INPUT MODE 1 or 3, 818 cards
955 static int pcl818_ai_cmd_mode(int mode, comedi_device * dev,
956 comedi_subdevice * s)
958 comedi_cmd *cmd = &s->async->cmd;
959 int divisor1, divisor2;
962 rt_printk("pcl818_ai_cmd_mode()\n");
963 if ((!dev->irq) && (!devpriv->dma_rtc)) {
964 comedi_error(dev, "IRQ not defined!");
968 if (devpriv->irq_blocked)
971 start_pacer(dev, -1, 0, 0); // stop pacer
973 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
977 setup_channel_list(dev, s, devpriv->ai_chanlist,
978 devpriv->ai_n_chan, seglen);
982 devpriv->ai_act_scan = devpriv->ai_scans;
983 devpriv->ai_act_chan = 0;
984 devpriv->irq_blocked = 1;
985 devpriv->irq_was_now_closed = 0;
986 devpriv->neverending_ai = 0;
987 devpriv->act_chanlist_pos = 0;
988 devpriv->dma_runs_to_end = 0;
990 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
991 devpriv->neverending_ai = 1; //well, user want neverending
994 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
995 &divisor2, &cmd->convert_arg, TRIG_ROUND_NEAREST);
996 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
1000 if (divisor2 == 1) {
1006 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1008 switch (devpriv->dma) {
1011 if (devpriv->dma_rtc == 0) {
1012 pcl818_ai_mode13dma_int(mode, dev, s);
1016 pcl818_ai_mode13dma_rtc(mode, dev, s);
1025 // rt_printk("IRQ\n");
1027 devpriv->ai_mode = INT_TYPE_AI1_INT;
1028 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1030 devpriv->ai_mode = INT_TYPE_AI3_INT;
1031 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1035 outb(1, dev->iobase + PCL818_FI_ENABLE); // enable FIFO
1037 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1038 outb(0x03, dev->iobase + PCL818_CONTROL); /* Pacer */
1040 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1041 outb(0x02, dev->iobase + PCL818_CONTROL);
1046 start_pacer(dev, mode, divisor1, divisor2);
1049 switch (devpriv->ai_mode) {
1050 case INT_TYPE_AI1_DMA_RTC:
1051 case INT_TYPE_AI3_DMA_RTC:
1052 set_rtc_irq_bit(1); /* start RTC */
1056 rt_printk("pcl818_ai_cmd_mode() end\n");
1062 ==============================================================================
1063 ANALOG OUTPUT MODE 1 or 3, 818 cards
1065 #ifdef PCL818_MODE13_AO
1066 static int pcl818_ao_mode13(int mode, comedi_device * dev, comedi_subdevice * s,
1069 int divisor1, divisor2;
1072 comedi_error(dev, "IRQ not defined!");
1076 if (devpriv->irq_blocked)
1079 start_pacer(dev, -1, 0, 0); // stop pacer
1081 devpriv->int13_act_scan = it->n;
1082 devpriv->int13_act_chan = 0;
1083 devpriv->irq_blocked = 1;
1084 devpriv->irq_was_now_closed = 0;
1085 devpriv->neverending_ai = 0;
1086 devpriv->act_chanlist_pos = 0;
1089 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1090 &divisor2, &it->trigvar, TRIG_ROUND_NEAREST);
1091 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1095 if (divisor2 == 1) {
1101 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1103 devpriv->int818_mode = INT_TYPE_AO1_INT;
1104 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1106 devpriv->int818_mode = INT_TYPE_AO3_INT;
1107 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1110 start_pacer(dev, mode, divisor1, divisor2);
1116 ==============================================================================
1117 ANALOG OUTPUT MODE 1, 818 cards
1119 static int pcl818_ao_mode1(comedi_device * dev, comedi_subdevice * s,
1122 return pcl818_ao_mode13(1, dev, s, it);
1126 ==============================================================================
1127 ANALOG OUTPUT MODE 3, 818 cards
1129 static int pcl818_ao_mode3(comedi_device * dev, comedi_subdevice * s,
1132 return pcl818_ao_mode13(3, dev, s, it);
1138 ==============================================================================
1139 Start/stop pacer onboard pacer
1141 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1,
1142 unsigned int divisor2)
1144 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1145 outb(0x74, dev->iobase + PCL818_CTRCTL);
1149 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1150 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1151 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1152 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1157 ==============================================================================
1158 Check if channel list from user is builded correctly
1159 If it's ok, then program scan/gain logic
1161 static int check_channel_list(comedi_device * dev, comedi_subdevice * s,
1162 unsigned int *chanlist, unsigned int n_chan)
1164 unsigned int chansegment[16];
1165 unsigned int i, nowmustbechan, seglen, segpos;
1167 /* correct channel and range number check itself comedi/range.c */
1169 comedi_error(dev, "range/channel list is empty!");
1174 // first channel is everytime ok
1175 chansegment[0] = chanlist[0];
1176 // build part of chanlist
1177 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1178 // rt_printk("%d. %d %d\n",i,CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));
1179 // we detect loop, this must by finish
1180 if (chanlist[0] == chanlist[i])
1183 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1184 if (nowmustbechan != CR_CHAN(chanlist[i])) { // channel list isn't continous :-(
1186 ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1187 dev->minor, i, CR_CHAN(chanlist[i]),
1188 nowmustbechan, CR_CHAN(chanlist[0]));
1191 // well, this is next correct channel in list
1192 chansegment[i] = chanlist[i];
1195 // check whole chanlist
1196 for (i = 0, segpos = 0; i < n_chan; i++) {
1197 //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]));
1198 if (chanlist[i] != chansegment[i % seglen]) {
1200 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1201 dev->minor, i, CR_CHAN(chansegment[i]),
1202 CR_RANGE(chansegment[i]),
1203 CR_AREF(chansegment[i]),
1204 CR_CHAN(chanlist[i % seglen]),
1205 CR_RANGE(chanlist[i % seglen]),
1206 CR_AREF(chansegment[i % seglen]));
1207 return 0; // chan/gain list is strange
1213 rt_printk("check_channel_list: seglen %d\n", seglen);
1217 static void setup_channel_list(comedi_device * dev, comedi_subdevice * s,
1218 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen)
1222 devpriv->act_chanlist_len = seglen;
1223 devpriv->act_chanlist_pos = 0;
1225 for (i = 0; i < seglen; i++) { // store range list to card
1226 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1227 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1228 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1233 /* select channel interval to scan */
1234 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1235 1] << 4), dev->iobase + PCL818_MUX);
1239 ==============================================================================
1240 Check if board is switched to SE (1) or DIFF(0) mode
1242 static int check_single_ended(unsigned int port)
1244 if (inb(port + PCL818_STATUS) & 0x20) {
1252 ==============================================================================
1254 static int ai_cmdtest(comedi_device * dev, comedi_subdevice * s,
1258 int tmp, divisor1, divisor2;
1260 /* step 1: make sure trigger sources are trivially valid */
1262 tmp = cmd->start_src;
1263 cmd->start_src &= TRIG_NOW;
1264 if (!cmd->start_src || tmp != cmd->start_src)
1267 tmp = cmd->scan_begin_src;
1268 cmd->scan_begin_src &= TRIG_FOLLOW;
1269 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1272 tmp = cmd->convert_src;
1273 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1274 if (!cmd->convert_src || tmp != cmd->convert_src)
1277 tmp = cmd->scan_end_src;
1278 cmd->scan_end_src &= TRIG_COUNT;
1279 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1282 tmp = cmd->stop_src;
1283 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1284 if (!cmd->stop_src || tmp != cmd->stop_src)
1291 /* step 2: make sure trigger sources are unique and mutually compatible */
1293 if (cmd->start_src != TRIG_NOW) {
1294 cmd->start_src = TRIG_NOW;
1297 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1298 cmd->scan_begin_src = TRIG_FOLLOW;
1301 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1304 if (cmd->scan_end_src != TRIG_COUNT) {
1305 cmd->scan_end_src = TRIG_COUNT;
1309 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1316 /* step 3: make sure arguments are trivially compatible */
1318 if (cmd->start_arg != 0) {
1323 if (cmd->scan_begin_arg != 0) {
1324 cmd->scan_begin_arg = 0;
1328 if (cmd->convert_src == TRIG_TIMER) {
1329 if (cmd->convert_arg < this_board->ns_min) {
1330 cmd->convert_arg = this_board->ns_min;
1333 } else { /* TRIG_EXT */
1334 if (cmd->convert_arg != 0) {
1335 cmd->convert_arg = 0;
1340 if (!cmd->chanlist_len) {
1341 cmd->chanlist_len = 1;
1344 if (cmd->chanlist_len > s->n_chan) {
1345 cmd->chanlist_len = s->n_chan;
1348 if (cmd->scan_end_arg != cmd->chanlist_len) {
1349 cmd->scan_end_arg = cmd->chanlist_len;
1352 if (cmd->stop_src == TRIG_COUNT) {
1353 if (!cmd->stop_arg) {
1357 } else { /* TRIG_NONE */
1358 if (cmd->stop_arg != 0) {
1368 /* step 4: fix up any arguments */
1370 if (cmd->convert_src == TRIG_TIMER) {
1371 tmp = cmd->convert_arg;
1372 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1373 &divisor2, &cmd->convert_arg,
1374 cmd->flags & TRIG_ROUND_MASK);
1375 if (cmd->convert_arg < this_board->ns_min)
1376 cmd->convert_arg = this_board->ns_min;
1377 if (tmp != cmd->convert_arg)
1385 /* step 5: complain about special chanlist considerations */
1387 if (cmd->chanlist) {
1388 if (!check_channel_list(dev, s, cmd->chanlist,
1390 return 5; // incorrect channels list
1397 ==============================================================================
1399 static int ai_cmd(comedi_device * dev, comedi_subdevice * s)
1401 comedi_cmd *cmd = &s->async->cmd;
1404 rt_printk("pcl818_ai_cmd()\n");
1405 devpriv->ai_n_chan = cmd->chanlist_len;
1406 devpriv->ai_chanlist = cmd->chanlist;
1407 devpriv->ai_flags = cmd->flags;
1408 devpriv->ai_data_len = s->async->prealloc_bufsz;
1409 devpriv->ai_data = s->async->prealloc_buf;
1410 devpriv->ai_timer1 = 0;
1411 devpriv->ai_timer2 = 0;
1413 if (cmd->stop_src == TRIG_COUNT) {
1414 devpriv->ai_scans = cmd->stop_arg;
1416 devpriv->ai_scans = 0;
1419 if (cmd->scan_begin_src == TRIG_FOLLOW) { // mode 1, 3
1420 if (cmd->convert_src == TRIG_TIMER) { // mode 1
1421 devpriv->ai_timer1 = cmd->convert_arg;
1422 retval = pcl818_ai_cmd_mode(1, dev, s);
1423 rt_printk("pcl818_ai_cmd() end\n");
1426 if (cmd->convert_src == TRIG_EXT) { // mode 3
1427 return pcl818_ai_cmd_mode(3, dev, s);
1435 ==============================================================================
1436 cancel any mode 1-4 AI
1438 static int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s)
1440 if (devpriv->irq_blocked > 0) {
1441 rt_printk("pcl818_ai_cancel()\n");
1442 devpriv->irq_was_now_closed = devpriv->ai_mode;
1443 devpriv->ai_mode = 0;
1445 switch (devpriv->irq_was_now_closed) {
1447 case INT_TYPE_AI1_DMA_RTC:
1448 case INT_TYPE_AI3_DMA_RTC:
1449 set_rtc_irq_bit(0); // stop RTC
1450 del_timer(&devpriv->rtc_irq_timer);
1452 case INT_TYPE_AI1_DMA:
1453 case INT_TYPE_AI3_DMA:
1454 if (devpriv->neverending_ai) {
1455 /* wait for running dma transfer to end, do cleanup in interrupt */
1458 disable_dma(devpriv->dma);
1459 case INT_TYPE_AI1_INT:
1460 case INT_TYPE_AI3_INT:
1461 case INT_TYPE_AI1_FIFO:
1462 case INT_TYPE_AI3_FIFO:
1463 #ifdef PCL818_MODE13_AO
1464 case INT_TYPE_AO1_INT:
1465 case INT_TYPE_AO3_INT:
1467 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1469 start_pacer(dev, -1, 0, 0);
1470 outb(0, dev->iobase + PCL818_AD_LO);
1471 inb(dev->iobase + PCL818_AD_LO);
1472 inb(dev->iobase + PCL818_AD_HI);
1473 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1474 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1475 if (devpriv->usefifo) { // FIFO shutdown
1476 outb(0, dev->iobase + PCL818_FI_INTCLR);
1477 outb(0, dev->iobase + PCL818_FI_FLUSH);
1478 outb(0, dev->iobase + PCL818_FI_ENABLE);
1480 devpriv->irq_blocked = 0;
1481 devpriv->last_int_sub = s;
1482 devpriv->neverending_ai = 0;
1488 rt_printk("pcl818_ai_cancel() end\n");
1493 ==============================================================================
1496 static int pcl818_check(unsigned long iobase)
1498 outb(0x00, iobase + PCL818_MUX);
1500 if (inb(iobase + PCL818_MUX) != 0x00)
1501 return 1; //there isn't card
1502 outb(0x55, iobase + PCL818_MUX);
1504 if (inb(iobase + PCL818_MUX) != 0x55)
1505 return 1; //there isn't card
1506 outb(0x00, iobase + PCL818_MUX);
1508 outb(0x18, iobase + PCL818_CONTROL);
1510 if (inb(iobase + PCL818_CONTROL) != 0x18)
1511 return 1; //there isn't card
1512 return 0; // ok, card exist
1516 ==============================================================================
1517 reset whole PCL-818 cards
1519 static void pcl818_reset(comedi_device * dev)
1521 if (devpriv->usefifo) { // FIFO shutdown
1522 outb(0, dev->iobase + PCL818_FI_INTCLR);
1523 outb(0, dev->iobase + PCL818_FI_FLUSH);
1524 outb(0, dev->iobase + PCL818_FI_ENABLE);
1526 outb(0, dev->iobase + PCL818_DA_LO); // DAC=0V
1527 outb(0, dev->iobase + PCL818_DA_HI);
1529 outb(0, dev->iobase + PCL818_DO_HI); // DO=$0000
1530 outb(0, dev->iobase + PCL818_DO_LO);
1532 outb(0, dev->iobase + PCL818_CONTROL);
1533 outb(0, dev->iobase + PCL818_CNTENABLE);
1534 outb(0, dev->iobase + PCL818_MUX);
1535 outb(0, dev->iobase + PCL818_CLRINT);
1536 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1537 outb(0x70, dev->iobase + PCL818_CTRCTL);
1538 outb(0x30, dev->iobase + PCL818_CTRCTL);
1539 if (this_board->is_818) {
1540 outb(0, dev->iobase + PCL818_RANGE);
1542 outb(0, dev->iobase + PCL718_DA2_LO);
1543 outb(0, dev->iobase + PCL718_DA2_HI);
1549 ==============================================================================
1550 Enable(1)/disable(0) periodic interrupts from RTC
1552 static int set_rtc_irq_bit(unsigned char bit)
1555 unsigned long flags;
1559 if (RTC_timer_lock > 1)
1563 if (RTC_timer_lock < 0)
1565 if (RTC_timer_lock > 0)
1571 val = CMOS_READ(RTC_CONTROL);
1577 CMOS_WRITE(val, RTC_CONTROL);
1578 CMOS_READ(RTC_INTR_FLAGS);
1579 restore_flags(flags);
1584 ==============================================================================
1585 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1587 static void rtc_dropped_irq(unsigned long data)
1589 comedi_device *dev = (void *)data;
1590 unsigned long flags, tmp;
1592 switch (devpriv->int818_mode) {
1593 case INT_TYPE_AI1_DMA_RTC:
1594 case INT_TYPE_AI3_DMA_RTC:
1595 mod_timer(&devpriv->rtc_irq_timer,
1596 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1599 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1600 restore_flags(flags);
1606 ==============================================================================
1607 Set frequency of interrupts from RTC
1609 static int rtc_setfreq_irq(int freq)
1614 unsigned long flags;
1621 while (freq > (1 << tmp))
1624 rtc_freq = 1 << tmp;
1628 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1630 CMOS_WRITE(val, RTC_FREQ_SELECT);
1631 restore_flags(flags);
1637 ==============================================================================
1638 Free any resources that we have claimed
1640 static void free_resources(comedi_device * dev)
1642 //rt_printk("free_resource()\n");
1644 pcl818_ai_cancel(dev, devpriv->sub_ai);
1647 free_dma(devpriv->dma);
1648 if (devpriv->dmabuf[0])
1649 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1650 if (devpriv->dmabuf[1])
1651 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1653 if (devpriv->rtc_irq)
1654 comedi_free_irq(devpriv->rtc_irq, dev);
1655 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1656 if (devpriv->rtc_iobase)
1657 release_region(devpriv->rtc_iobase,
1658 devpriv->rtc_iosize);
1660 if (devpriv->dma_rtc)
1666 free_irq(dev->irq, dev);
1668 release_region(dev->iobase, devpriv->io_range);
1669 //rt_printk("free_resource() end\n");
1673 ==============================================================================
1678 static int pcl818_attach(comedi_device * dev, comedi_devconfig * it)
1681 unsigned long iobase;
1682 unsigned int irq, dma;
1683 unsigned long pages;
1684 comedi_subdevice *s;
1686 if ((ret = alloc_private(dev, sizeof(pcl818_private))) < 0)
1687 return ret; /* Can't alloc mem */
1689 /* claim our I/O space */
1690 iobase = it->options[0];
1691 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1692 dev->minor, this_board->name, iobase);
1693 devpriv->io_range = this_board->io_range;
1694 if ((this_board->fifo) && (it->options[2] == -1)) { // we've board with FIFO and we want to use FIFO
1695 devpriv->io_range = PCLx1xFIFO_RANGE;
1696 devpriv->usefifo = 1;
1698 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1699 rt_printk("I/O port conflict\n");
1703 dev->iobase = iobase;
1705 if (pcl818_check(iobase)) {
1706 rt_printk(", I can't detect board. FAIL!\n");
1710 /* set up some name stuff */
1711 dev->board_name = this_board->name;
1714 if (this_board->IRQbits != 0) { /* board support IRQ */
1715 irq = it->options[1];
1716 if (irq) { /* we want to use IRQ */
1717 if (((1 << irq) & this_board->IRQbits) == 0) {
1719 (", IRQ %u is out of allowed range, DISABLING IT",
1721 irq = 0; /* Bad IRQ */
1723 if (comedi_request_irq(irq, interrupt_pcl818, 0,
1726 (", unable to allocate IRQ %u, DISABLING IT",
1728 irq = 0; /* Can't use IRQ */
1730 rt_printk(", irq=%u", irq);
1738 devpriv->irq_free = 1;
1739 } /* 1=we have allocated irq */
1741 devpriv->irq_free = 0;
1743 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1744 devpriv->ai_mode = 0; /* mode of irq */
1747 /* grab RTC for DMA operations */
1748 devpriv->dma_rtc = 0;
1749 if (it->options[2] > 0) { // we want to use DMA
1750 if (RTC_lock == 0) {
1751 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1755 devpriv->rtc_iobase = RTC_PORT(0);
1756 devpriv->rtc_iosize = RTC_IO_EXTENT;
1758 if (!comedi_request_irq(RTC_IRQ,
1759 interrupt_pcl818_ai_mode13_dma_rtc, 0,
1760 "pcl818 DMA (RTC)", dev)) {
1761 devpriv->dma_rtc = 1;
1762 devpriv->rtc_irq = RTC_IRQ;
1763 rt_printk(", dma_irq=%u", devpriv->rtc_irq);
1766 if (RTC_lock == 0) {
1767 if (devpriv->rtc_iobase)
1768 release_region(devpriv->rtc_iobase,
1769 devpriv->rtc_iosize);
1771 devpriv->rtc_iobase = 0;
1772 devpriv->rtc_iosize = 0;
1781 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1782 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1783 if (this_board->DMAbits != 0) { /* board support DMA */
1784 dma = it->options[2];
1786 goto no_dma; /* DMA disabled */
1787 if (((1 << dma) & this_board->DMAbits) == 0) {
1788 rt_printk(", DMA is out of allowed range, FAIL!\n");
1789 return -EINVAL; /* Bad DMA */
1791 ret = request_dma(dma, "pcl818");
1793 rt_printk(", unable to allocate DMA %u, FAIL!\n", dma);
1794 return -EBUSY; /* DMA isn't free */
1797 rt_printk(", dma=%u", dma);
1798 pages = 2; /* we need 16KB */
1799 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1800 if (!devpriv->dmabuf[0]) {
1801 rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1802 /* maybe experiment with try_to_free_pages() will help .... */
1803 return -EBUSY; /* no buffer :-( */
1805 devpriv->dmapages[0] = pages;
1806 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1807 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1808 //rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE);
1809 if (devpriv->dma_rtc == 0) { // we must do duble buff :-(
1810 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1811 if (!devpriv->dmabuf[1]) {
1813 (", unable to allocate DMA buffer, FAIL!\n");
1816 devpriv->dmapages[1] = pages;
1817 devpriv->hwdmaptr[1] =
1818 virt_to_bus((void *)devpriv->dmabuf[1]);
1819 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1825 if ((ret = alloc_subdevices(dev, 4)) < 0)
1828 s = dev->subdevices + 0;
1829 if (!this_board->n_aichan_se) {
1830 s->type = COMEDI_SUBD_UNUSED;
1832 s->type = COMEDI_SUBD_AI;
1833 devpriv->sub_ai = s;
1834 s->subdev_flags = SDF_READABLE;
1835 if (check_single_ended(dev->iobase)) {
1836 s->n_chan = this_board->n_aichan_se;
1837 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1838 printk(", %dchans S.E. DAC", s->n_chan);
1840 s->n_chan = this_board->n_aichan_diff;
1841 s->subdev_flags |= SDF_DIFF;
1842 printk(", %dchans DIFF DAC", s->n_chan);
1844 s->maxdata = this_board->ai_maxdata;
1845 s->len_chanlist = s->n_chan;
1846 s->range_table = this_board->ai_range_type;
1847 s->cancel = pcl818_ai_cancel;
1848 s->insn_read = pcl818_ai_insn_read;
1849 if ((irq) || (devpriv->dma_rtc)) {
1850 dev->read_subdev = s;
1851 s->subdev_flags |= SDF_CMD_READ;
1852 s->do_cmdtest = ai_cmdtest;
1855 if (this_board->is_818) {
1856 if ((it->options[4] == 1) || (it->options[4] == 10))
1857 s->range_table = &range_pcl818l_h_ai; // secondary range list jumper selectable
1859 switch (it->options[4]) {
1861 s->range_table = &range_bipolar10;
1864 s->range_table = &range_bipolar5;
1867 s->range_table = &range_bipolar2_5;
1870 s->range_table = &range718_bipolar1;
1873 s->range_table = &range718_bipolar0_5;
1876 s->range_table = &range_unipolar10;
1879 s->range_table = &range_unipolar5;
1882 s->range_table = &range718_unipolar2;
1885 s->range_table = &range718_unipolar1;
1888 s->range_table = &range_unknown;
1894 s = dev->subdevices + 1;
1895 if (!this_board->n_aochan) {
1896 s->type = COMEDI_SUBD_UNUSED;
1898 s->type = COMEDI_SUBD_AO;
1899 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1900 s->n_chan = this_board->n_aochan;
1901 s->maxdata = this_board->ao_maxdata;
1902 s->len_chanlist = this_board->n_aochan;
1903 s->range_table = this_board->ao_range_type;
1904 s->insn_read = pcl818_ao_insn_read;
1905 s->insn_write = pcl818_ao_insn_write;
1907 #ifdef PCL818_MODE13_AO
1909 s->trig[1] = pcl818_ao_mode1;
1910 s->trig[3] = pcl818_ao_mode3;
1914 if (this_board->is_818) {
1915 if ((it->options[4] == 1) || (it->options[4] == 10))
1916 s->range_table = &range_unipolar10;
1917 if (it->options[4] == 2)
1918 s->range_table = &range_unknown;
1920 if ((it->options[5] == 1) || (it->options[5] == 10))
1921 s->range_table = &range_unipolar10;
1922 if (it->options[5] == 2)
1923 s->range_table = &range_unknown;
1927 s = dev->subdevices + 2;
1928 if (!this_board->n_dichan) {
1929 s->type = COMEDI_SUBD_UNUSED;
1931 s->type = COMEDI_SUBD_DI;
1932 s->subdev_flags = SDF_READABLE;
1933 s->n_chan = this_board->n_dichan;
1935 s->len_chanlist = this_board->n_dichan;
1936 s->range_table = &range_digital;
1937 s->insn_bits = pcl818_di_insn_bits;
1940 s = dev->subdevices + 3;
1941 if (!this_board->n_dochan) {
1942 s->type = COMEDI_SUBD_UNUSED;
1944 s->type = COMEDI_SUBD_DO;
1945 s->subdev_flags = SDF_WRITABLE;
1946 s->n_chan = this_board->n_dochan;
1948 s->len_chanlist = this_board->n_dochan;
1949 s->range_table = &range_digital;
1950 s->insn_bits = pcl818_do_insn_bits;
1953 /* select 1/10MHz oscilator */
1954 if ((it->options[3] == 0) || (it->options[3] == 10)) {
1955 devpriv->i8253_osc_base = 100;
1957 devpriv->i8253_osc_base = 1000;
1960 /* max sampling speed */
1961 devpriv->ns_min = this_board->ns_min;
1963 if (!this_board->is_818) {
1964 if ((it->options[6] == 1) || (it->options[6] == 100))
1965 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1976 ==============================================================================
1979 static int pcl818_detach(comedi_device * dev)
1981 // rt_printk("comedi%d: pcl818: remove\n", dev->minor);
1982 free_resources(dev);