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 <linux/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 comedi_lrange range_pcl818h_ai = { 9, {
209 static comedi_lrange range_pcl818hg_ai = { 10, {
224 static comedi_lrange range_pcl818l_l_ai = { 4, {
231 static comedi_lrange range_pcl818l_h_ai = { 4, {
238 static comedi_lrange range718_bipolar1 = { 1, { BIP_RANGE(1), }};
239 static comedi_lrange range718_bipolar0_5 = { 1, { BIP_RANGE(0.5), }};
240 static comedi_lrange range718_unipolar2 = { 1, { UNI_RANGE(2), }};
241 static comedi_lrange range718_unipolar1 = { 1, { BIP_RANGE(1), }};
243 static int pcl818_attach(comedi_device *dev,comedi_devconfig *it);
244 static int pcl818_detach(comedi_device *dev);
247 static int RTC_lock = 0; /* RTC lock */
248 static int RTC_timer_lock = 0; /* RTC int lock */
252 const char *name; // driver name
253 int n_ranges; // len of range list
254 int n_aichan_se; // num of A/D chans in single ended mode
255 int n_aichan_diff; // num of A/D chans in diferencial mode
256 unsigned int ns_min; // minimal alllowed delay between samples (in ns)
257 int n_aochan; // num of D/A chans
258 int n_dichan; // num of DI chans
259 int n_dochan; // num of DO chans
260 comedi_lrange *ai_range_type; // default A/D rangelist
261 comedi_lrange *ao_range_type; // default D/A rangelist
262 unsigned int io_range; // len of IO space
263 unsigned int IRQbits; // allowed interrupts
264 unsigned int DMAbits; // allowed DMA chans
265 int ai_maxdata; // maxdata for A/D
266 int ao_maxdata; // maxdata for D/A
267 unsigned char fifo; // 1=board has FIFO
271 static boardtype boardtypes[] =
273 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
274 0x0a, 0xfff, 0xfff, 0, 1 },
275 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
276 0x0a, 0xfff, 0xfff, 0, 1 },
277 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
278 0x0a, 0xfff, 0xfff, 1, 1 },
279 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
280 0x0a, 0xfff, 0xfff, 1, 1 },
281 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
282 0x0a, 0xfff, 0xfff, 0, 1 },
283 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
284 0x0a, 0xfff, 0xfff, 0, 0 },
286 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
287 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
290 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
292 static comedi_driver driver_pcl818={
293 driver_name: "pcl818",
295 attach: pcl818_attach,
296 detach: pcl818_detach,
297 board_name: &boardtypes[0].name,
298 num_names: n_boardtypes,
299 offset: sizeof(boardtype),
301 COMEDI_INITCLEANUP(driver_pcl818);
305 unsigned int dma; // used DMA, 0=don't use DMA
306 int dma_rtc; // 1=RTC used with DMA, 0=no RTC alloc
307 unsigned int io_range;
309 unsigned long rtc_iobase; // RTC port region
310 unsigned int rtc_iosize;
311 unsigned int rtc_irq;
312 struct timer_list rtc_irq_timer;// timer for RTC sanity check
313 unsigned long rtc_freq; // RTC int freq
314 int rtc_irq_blocked;// 1=we now do AI with DMA&RTC
316 unsigned long dmabuf[2]; // pointers to begin of DMA buffers
317 unsigned int dmapages[2]; // len of DMA buffers in PAGE_SIZEs
318 unsigned int hwdmaptr[2]; // hardware address of DMA buffers
319 unsigned int hwdmasize[2]; // len of DMA buffers in Bytes
320 unsigned int dmasamplsize; // size in samples hwdmasize[0]/2
321 unsigned int last_top_dma; // DMA pointer in last RTC int
322 int next_dma_buf; // which DMA buffer will be used next round
323 long dma_runs_to_end;// how many we must permorm DMA transfer to end of record
324 unsigned long last_dma_run; // how many bytes we must transfer on last DMA page
325 unsigned char neverending_ai; // if=1, then we do neverending record (you must use cancel())
326 unsigned int ns_min; // manimal alllowed delay between samples (in us) for actual card
327 int i8253_osc_base; // 1/frequency of on board oscilator in ns
328 int irq_free; // 1=have allocated IRQ
329 int irq_blocked; // 1=IRQ now uses any subdev
330 int irq_was_now_closed;// when IRQ finish, there's stored int818_mode for last interrupt
331 int ai_mode; // who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma
332 comedi_subdevice *last_int_sub; // ptr to subdevice which now finish
333 int ai_act_scan; // how many scans we finished
334 int ai_act_chan; // actual position in actual scan
335 unsigned int act_chanlist[16];// MUX setting for actual AI operations
336 unsigned int act_chanlist_len;// how long is actual MUX list
337 unsigned int act_chanlist_pos;// actual position in MUX list
338 unsigned int ai_scans; // len of scanlist
339 unsigned int ai_n_chan; // how many channels is measured
340 unsigned int *ai_chanlist; // actaul chanlist
341 unsigned int ai_flags; // flaglist
342 unsigned int ai_data_len; // len of data buffer
343 sampl_t *ai_data; // data buffer
344 unsigned int ai_timer1; // timers
345 unsigned int ai_timer2;
346 comedi_subdevice *sub_ai; // ptr to AI subdevice
347 unsigned char usefifo; // 1=use fifo
348 lsampl_t ao_readback[2];
352 static unsigned int muxonechan[] ={ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // used for gain list programming
353 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
355 #define devpriv ((pcl818_private *)dev->private)
356 #define this_board ((boardtype *)dev->board_ptr)
359 ==============================================================================
361 static void setup_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist,
362 unsigned int n_chan, unsigned int seglen);
363 static int check_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist,
364 unsigned int n_chan);
366 static int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s);
367 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2);
370 static int set_rtc_irq_bit(unsigned char bit);
371 static void rtc_dropped_irq(unsigned long data);
372 static int rtc_setfreq_irq(int freq);
376 ==============================================================================
377 ANALOG INPUT MODE0, 818 cards, slow version
379 static int pcl818_ai_insn_read(comedi_device *dev, comedi_subdevice *s,
380 comedi_insn *insn, lsampl_t *data)
385 /* software trigger, DMA and INT off */
386 outb(0, dev->iobase+PCL818_CONTROL);
389 outb(muxonechan[CR_CHAN(insn->chanspec)],
390 dev->iobase+PCL818_MUX);
393 outb(CR_RANGE(insn->chanspec),
394 dev->iobase+PCL818_RANGE);
396 for(n=0;n<insn->n;n++){
398 /* clear INT (conversion end) flag */
399 outb(0, dev->iobase+PCL818_CLRINT);
401 /* start conversion */
402 outb(0, dev->iobase+PCL818_AD_LO);
406 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
410 comedi_error(dev,"A/D insn timeout");
411 /* clear INT (conversion end) flag */
412 outb(0, dev->iobase+PCL818_CLRINT);
416 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
417 (inb(dev->iobase + PCL818_AD_LO) >> 4));
424 ==============================================================================
425 ANALOG OUTPUT MODE0, 818 cards
426 only one sample per call is supported
428 static int pcl818_ao_insn_read(comedi_device *dev, comedi_subdevice *s,
429 comedi_insn *insn, lsampl_t *data)
432 int chan = CR_CHAN(insn->chanspec);
434 for(n=0;n<insn->n;n++){
435 data[n] = devpriv->ao_readback[chan];
441 static int pcl818_ao_insn_write(comedi_device *dev, comedi_subdevice *s,
442 comedi_insn *insn, lsampl_t *data)
445 int chan = CR_CHAN(insn->chanspec);
447 for(n=0;n<insn->n;n++){
448 devpriv->ao_readback[chan] = data[n];
449 outb((data[n] & 0x000f) << 4, dev->iobase+
450 (chan)?PCL718_DA2_LO:PCL818_DA_LO);
451 outb((data[n] & 0x0ff0) >> 4, dev->iobase+
452 (chan)?PCL718_DA2_HI:PCL818_DA_HI);
459 ==============================================================================
460 DIGITAL INPUT MODE0, 818 cards
462 only one sample per call is supported
464 static int pcl818_di_insn_bits(comedi_device *dev, comedi_subdevice *s,
465 comedi_insn *insn, lsampl_t *data)
467 if(insn->n!=2)return -EINVAL;
469 data[1] = inb(dev->iobase + PCL818_DI_LO) |
470 (inb(dev->iobase + PCL818_DI_HI) << 8);
476 ==============================================================================
477 DIGITAL OUTPUT MODE0, 818 cards
479 only one sample per call is supported
481 static int pcl818_do_insn_bits(comedi_device *dev, comedi_subdevice *s,
482 comedi_insn *insn, lsampl_t *data)
484 if(insn->n!=2)return -EINVAL;
486 s->state &= ~data[0];
487 s->state |= (data[0]&data[1]);
489 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
490 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
498 ==============================================================================
499 analog input interrupt mode 1 & 3, 818 cards
500 one sample per interrupt version
502 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
504 comedi_device *dev = d;
505 comedi_subdevice *s = dev->subdevices + 0;
507 int timeout=50; /* wait max 50us */
510 if (inb(dev->iobase + PCL818_STATUS) & 0x10) goto conv_finish;
513 outb(0,dev->iobase+PCL818_STATUS); /* clear INT request */
514 comedi_error(dev,"A/D mode1/3 IRQ without DRDY!");
515 pcl818_ai_cancel(dev,s);
516 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
517 comedi_event(dev, s, s->async->events);
521 low=inb(dev->iobase + PCL818_AD_LO);
522 comedi_buf_put( s->async,
523 ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4)) ); // get one sample
524 outb(0,dev->iobase+PCL818_CLRINT); /* clear INT request */
526 if ((low & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
527 rt_printk("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",(low & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos]);
528 pcl818_ai_cancel(dev,s);
529 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
530 comedi_event(dev, s, s->async->events);
533 if (s->async->cur_chan == 0) {
535 devpriv->ai_act_scan--;
538 if (!devpriv->neverending_ai){
539 if ( devpriv->ai_act_scan == 0 ) { /* all data sampled */
540 pcl818_ai_cancel(dev,s);
541 s->async->events |= COMEDI_CB_EOA;
544 comedi_event(dev, s, s->async->events);
549 ==============================================================================
550 analog input dma mode 1 & 3, 818 cards
552 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
554 comedi_device *dev = d;
555 comedi_subdevice *s = dev->subdevices + 0;
560 disable_dma(devpriv->dma);
561 devpriv->next_dma_buf=1-devpriv->next_dma_buf;
562 if ((devpriv->dma_runs_to_end)>-1 || devpriv->neverending_ai) { // switch dma bufs
563 set_dma_mode(devpriv->dma, DMA_MODE_READ);
564 flags=claim_dma_lock();
565 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
566 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) { set_dma_count(devpriv->dma, devpriv->hwdmasize[devpriv->next_dma_buf]); }
567 else { set_dma_count(devpriv->dma, devpriv->last_dma_run); }
568 release_dma_lock(flags);
569 enable_dma(devpriv->dma);
571 rt_printk("comedi: A/D mode1/3 IRQ \n");
573 devpriv->dma_runs_to_end--;
574 outb(0,dev->iobase+PCL818_CLRINT); /* clear INT request */
575 ptr=(sampl_t *)devpriv->dmabuf[1-devpriv->next_dma_buf];
577 len=devpriv->hwdmasize[0] >> 1;
580 for (i=0;i<len;i++) {
581 if ((ptr[bufptr] & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
582 rt_printk("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",(ptr[bufptr] & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos], devpriv->act_chanlist_pos);
583 pcl818_ai_cancel(dev,s);
584 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
585 comedi_event(dev, s, s->async->events);
589 comedi_buf_put( s->async, ptr[bufptr++] >> 4 ); // get one sample
591 devpriv->act_chanlist_pos++;
592 if ( devpriv->act_chanlist_pos >= devpriv->act_chanlist_len ) {
593 devpriv->ai_act_scan--;
594 devpriv->act_chanlist_pos = 0;
597 if (!devpriv->neverending_ai)
598 if ( devpriv->ai_act_scan == 0 ) { /* all data sampled */
599 pcl818_ai_cancel(dev,s);
600 s->async->events |= COMEDI_CB_EOA;
601 comedi_event(dev, s, s->async->events);
602 // printk("done int ai13 dma\n");
607 if (len>0) comedi_event(dev, s, s->async->events);
613 ==============================================================================
614 analog input dma mode 1 & 3 over RTC, 818 cards
616 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
618 comedi_device *dev = d;
619 comedi_subdevice *s = dev->subdevices + 0;
621 unsigned int top1,top2,i,bufptr;
623 sampl_t *dmabuf=(sampl_t *)devpriv->dmabuf[0];
626 switch(devpriv->ai_mode) {
627 case INT_TYPE_AI1_DMA_RTC:
628 case INT_TYPE_AI3_DMA_RTC:
629 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
630 mod_timer(&devpriv->rtc_irq_timer, jiffies + HZ/devpriv->rtc_freq + 2*HZ/100);
632 for (i=0; i<10; i++) {
633 top1=get_dma_residue(devpriv->dma);
634 top2=get_dma_residue(devpriv->dma);
635 if (top1==top2) break;
638 if (top1!=top2) return IRQ_HANDLED;
639 top1=devpriv->hwdmasize[0]-top1; // where is now DMA in buffer
641 ofs_dats=top1-devpriv->last_top_dma; // new samples from last call
642 if (ofs_dats<0) ofs_dats=(devpriv->dmasamplsize)+ofs_dats;
643 if (!ofs_dats) return IRQ_HANDLED; // exit=no new samples from last call
645 i=devpriv->last_top_dma-1;
646 i&=(devpriv->dmasamplsize-1);
648 if (dmabuf[i]!=MAGIC_DMA_WORD) { // DMA overflow!
649 comedi_error(dev,"A/D mode1/3 DMA buffer overflow!");
650 //rt_printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize);
651 pcl818_ai_cancel(dev,s);
652 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
653 comedi_event(dev, s, s->async->events);
656 //rt_printk("r %ld ",ofs_dats);
658 bufptr=devpriv->last_top_dma;
660 for (i=0; i<ofs_dats; i++) {
661 if ((dmabuf[bufptr] & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
662 rt_printk("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",(dmabuf[bufptr] & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos]);
663 pcl818_ai_cancel(dev,s);
664 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
665 comedi_event(dev, s, s->async->events);
669 comedi_buf_put( s->async, dmabuf[bufptr++] >> 4); // get one sample
670 bufptr&=(devpriv->dmasamplsize-1);
672 if(s->async->cur_chan == 0){
673 devpriv->ai_act_scan--;
676 if (!devpriv->neverending_ai)
677 if ( devpriv->ai_act_scan == 0 ) { /* all data sampled */
678 pcl818_ai_cancel(dev,s);
679 s->async->events |= COMEDI_CB_EOA;
680 comedi_event(dev, s, s->async->events);
681 //printk("done int ai13 dma\n");
686 devpriv->last_top_dma=bufptr;
688 bufptr&=(devpriv->dmasamplsize-1);
689 dmabuf[bufptr]=MAGIC_DMA_WORD;
690 comedi_event(dev, s, s->async->events);
701 ==============================================================================
702 analog input interrupt mode 1 & 3, 818HD/HG cards
704 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
706 comedi_device *dev = d;
707 comedi_subdevice *s = dev->subdevices + 0;
710 outb(0, dev->iobase + PCL818_FI_INTCLR); // clear fifo int request
712 lo=inb(dev->iobase + PCL818_FI_STATUS);
715 comedi_error(dev,"A/D mode1/3 FIFO overflow!");
716 pcl818_ai_cancel(dev,s);
717 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
718 comedi_event(dev, s, s->async->events);
723 comedi_error(dev,"A/D mode1/3 FIFO interrupt without data!");
724 pcl818_ai_cancel(dev,s);
725 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
726 comedi_event(dev, s, s->async->events);
730 if (lo&2) { len=512; }
733 for (i=0;i<len;i++) {
734 lo=inb(dev->iobase + PCL818_FI_DATALO);
735 if ((lo & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
736 rt_printk("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",(lo & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos]);
737 pcl818_ai_cancel(dev,s);
738 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
739 comedi_event(dev, s, s->async->events);
743 comedi_buf_put( s->async, (lo >> 4)|(inb(dev->iobase + PCL818_FI_DATAHI) << 4) ); // get one sample
745 if(s->async->cur_chan == 0){
746 devpriv->ai_act_scan--;
749 if (!devpriv->neverending_ai)
750 if ( devpriv->ai_act_scan == 0 ) { /* all data sampled */
751 pcl818_ai_cancel(dev,s);
752 s->async->events |= COMEDI_CB_EOA;
753 comedi_event(dev, s, s->async->events);
758 if (len>0) comedi_event(dev, s, s->async->events);
763 ==============================================================================
766 static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG)
768 comedi_device *dev = d;
772 comedi_error(dev, "premature interrupt");
778 switch (devpriv->ai_mode) {
779 case INT_TYPE_AI1_DMA:
780 case INT_TYPE_AI3_DMA:
781 return interrupt_pcl818_ai_mode13_dma(irq, d);
782 case INT_TYPE_AI1_INT:
783 case INT_TYPE_AI3_INT:
784 return interrupt_pcl818_ai_mode13_int(irq, d);
785 case INT_TYPE_AI1_FIFO:
786 case INT_TYPE_AI3_FIFO:
787 return interrupt_pcl818_ai_mode13_fifo(irq, d);
788 #ifdef PCL818_MODE13_AO
789 case INT_TYPE_AO1_INT:
790 case INT_TYPE_AO3_INT:
791 return interrupt_pcl818_ao_mode13_int(irq, d);
797 outb(0,dev->iobase+PCL818_CLRINT); /* clear INT request */
799 if ((!dev->irq)||(!devpriv->irq_free)||(!devpriv->irq_blocked)||(!devpriv->ai_mode)) {
800 if (devpriv->irq_was_now_closed) {
801 if ( devpriv->neverending_ai &&
802 (devpriv->ai_mode == INT_TYPE_AI1_DMA || devpriv->ai_mode == INT_TYPE_AI3_DMA) ) {
803 /* we had neverending ai but ai_cancel() has been called
804 the cleanup from ai_cancel() has been delayed until know
805 because the card doesn't seem to like being reprogrammed
806 while a DMA transfer is in progress
808 comedi_subdevice *s = dev->subdevices + 0;
809 devpriv->ai_mode = devpriv->irq_was_now_closed;
810 devpriv->irq_was_now_closed=0;
811 devpriv->neverending_ai = 0;
812 pcl818_ai_cancel(dev, s);
814 devpriv->irq_was_now_closed=0;
817 comedi_error(dev,"bad IRQ!");
821 comedi_error(dev,"IRQ from unknow source!");
826 ==============================================================================
827 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
829 static void pcl818_ai_mode13dma_int(int mode, comedi_device * dev, comedi_subdevice * s)
834 rt_printk("mode13dma_int, mode: %d\n", mode);
835 disable_dma(devpriv->dma); // disable dma
836 bytes=devpriv->hwdmasize[0];
837 if (!devpriv->neverending_ai) {
838 bytes=devpriv->ai_n_chan*devpriv->ai_scans*sizeof(sampl_t); // how many
839 devpriv->dma_runs_to_end=bytes / devpriv->hwdmasize[0]; // how many DMA pages we must fiil
840 devpriv->last_dma_run=bytes % devpriv->hwdmasize[0]; //on last dma transfer must be moved
841 devpriv->dma_runs_to_end--;
842 if (devpriv->dma_runs_to_end>=0) bytes=devpriv->hwdmasize[0];
845 devpriv->next_dma_buf=0;
846 set_dma_mode(devpriv->dma, DMA_MODE_READ);
847 flags=claim_dma_lock();
848 clear_dma_ff(devpriv->dma);
849 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
850 set_dma_count(devpriv->dma, bytes);
851 release_dma_lock(flags);
852 enable_dma(devpriv->dma);
855 devpriv->ai_mode=INT_TYPE_AI1_DMA;
856 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
858 devpriv->ai_mode=INT_TYPE_AI3_DMA;
859 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
865 ==============================================================================
866 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
868 static void pcl818_ai_mode13dma_rtc(int mode, comedi_device * dev, comedi_subdevice * s)
873 set_dma_mode(devpriv->dma, DMA_MODE_READ|DMA_AUTOINIT);
874 flags=claim_dma_lock();
875 clear_dma_ff(devpriv->dma);
876 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
877 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
878 release_dma_lock(flags);
879 enable_dma(devpriv->dma);
880 devpriv->last_top_dma=0; //devpriv->hwdmasize[0];
881 pole=(sampl_t *)devpriv->dmabuf[0];
882 devpriv->dmasamplsize=devpriv->hwdmasize[0]/2;
883 pole[devpriv->dmasamplsize-1]=MAGIC_DMA_WORD;
885 devpriv->rtc_freq=rtc_setfreq_irq(2048);
886 devpriv->rtc_irq_timer.expires=jiffies + HZ/devpriv->rtc_freq + 2*HZ/100;
887 devpriv->rtc_irq_timer.data=(unsigned long)dev;
888 devpriv->rtc_irq_timer.function=rtc_dropped_irq;
890 add_timer(&devpriv->rtc_irq_timer);
894 devpriv->int818_mode=INT_TYPE_AI1_DMA_RTC;
895 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
897 devpriv->int818_mode=INT_TYPE_AI3_DMA_RTC;
898 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
904 ==============================================================================
905 ANALOG INPUT MODE 1 or 3, 818 cards
907 static int pcl818_ai_cmd_mode(int mode, comedi_device * dev, comedi_subdevice * s)
909 comedi_cmd *cmd=&s->async->cmd;
910 int divisor1, divisor2;
913 rt_printk("pcl818_ai_cmd_mode()\n");
914 if ((!dev->irq)&&(!devpriv->dma_rtc)) {
915 comedi_error(dev,"IRQ not defined!");
919 if (devpriv->irq_blocked)
922 start_pacer(dev, -1, 0, 0); // stop pacer
924 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
926 if(seglen<1)return -EINVAL;
927 setup_channel_list(dev, s, devpriv->ai_chanlist,
928 devpriv->ai_n_chan,seglen);
932 devpriv->ai_act_scan=devpriv->ai_scans;
933 devpriv->ai_act_chan=0;
934 devpriv->irq_blocked=1;
935 devpriv->irq_was_now_closed=0;
936 devpriv->neverending_ai=0;
937 devpriv->act_chanlist_pos=0;
938 devpriv->dma_runs_to_end=0;
940 if ((devpriv->ai_scans==0)||(devpriv->ai_scans==-1)) devpriv->neverending_ai=1; //well, user want neverending
943 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,&divisor1,&divisor2,&cmd->convert_arg,TRIG_ROUND_NEAREST);
944 if (divisor1==1) { /* PCL718/818 crash if any divisor is set to 1 */
954 outb(0 , dev->iobase + PCL818_CNTENABLE); /* enable pacer */
956 switch (devpriv->dma) {
959 if (devpriv->dma_rtc==0) { pcl818_ai_mode13dma_int(mode, dev, s); }
961 else { pcl818_ai_mode13dma_rtc(mode, dev, s); }
963 else { return -EINVAL; }
967 // rt_printk("IRQ\n");
969 devpriv->ai_mode=INT_TYPE_AI1_INT;
970 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
972 devpriv->ai_mode=INT_TYPE_AI3_INT;
973 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
977 outb(1, dev->iobase + PCL818_FI_ENABLE); // enable FIFO
979 devpriv->ai_mode=INT_TYPE_AI1_FIFO;
980 outb(0x03, dev->iobase + PCL818_CONTROL); /* Pacer */
982 devpriv->ai_mode=INT_TYPE_AI3_FIFO;
983 outb(0x02, dev->iobase + PCL818_CONTROL);
988 start_pacer(dev, mode, divisor1, divisor2);
991 switch(devpriv->ai_mode) {
992 case INT_TYPE_AI1_DMA_RTC:
993 case INT_TYPE_AI3_DMA_RTC:
994 set_rtc_irq_bit(1); /* start RTC */
998 rt_printk("pcl818_ai_cmd_mode() end\n");
1005 ==============================================================================
1006 ANALOG OUTPUT MODE 1 or 3, 818 cards
1008 #ifdef PCL818_MODE13_AO
1009 static int pcl818_ao_mode13(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1011 int divisor1, divisor2;
1015 comedi_error(dev,"IRQ not defined!");
1019 if (devpriv->irq_blocked)
1022 start_pacer(dev, -1, 0, 0); // stop pacer
1024 devpriv->int13_act_scan=it->n;
1025 devpriv->int13_act_chan=0;
1026 devpriv->irq_blocked=1;
1027 devpriv->irq_was_now_closed=0;
1028 devpriv->neverending_ai=0;
1029 devpriv->act_chanlist_pos=0;
1032 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,&divisor1,&divisor2,&it->trigvar,TRIG_ROUND_NEAREST);
1033 if (divisor1==1) { /* PCL818 crash if any divisor is set to 1 */
1043 outb(0 , dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1045 devpriv->int818_mode=INT_TYPE_AO1_INT;
1046 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1048 devpriv->int818_mode=INT_TYPE_AO3_INT;
1049 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1052 start_pacer(dev, mode, divisor1, divisor2);
1058 ==============================================================================
1059 ANALOG OUTPUT MODE 1, 818 cards
1061 static int pcl818_ao_mode1(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1063 return pcl818_ao_mode13(1, dev, s, it);
1067 ==============================================================================
1068 ANALOG OUTPUT MODE 3, 818 cards
1070 static int pcl818_ao_mode3(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1072 return pcl818_ao_mode13(3, dev, s, it);
1078 ==============================================================================
1079 Start/stop pacer onboard pacer
1081 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2)
1083 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1084 outb(0x74, dev->iobase + PCL818_CTRCTL);
1088 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1089 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1090 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1091 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1096 ==============================================================================
1097 Check if channel list from user is builded correctly
1098 If it's ok, then program scan/gain logic
1100 static int check_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist,
1101 unsigned int n_chan)
1103 unsigned int chansegment[16];
1104 unsigned int i, nowmustbechan, seglen, segpos;
1106 /* correct channel and range number check itself comedi/range.c */
1108 comedi_error(dev,"range/channel list is empty!");
1113 // first channel is everytime ok
1114 chansegment[0]=chanlist[0];
1115 // build part of chanlist
1116 for (i=1, seglen=1; i<n_chan; i++, seglen++) {
1117 // rt_printk("%d. %d %d\n",i,CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));
1118 // we detect loop, this must by finish
1119 if (chanlist[0]==chanlist[i]) break;
1120 nowmustbechan=(CR_CHAN(chansegment[i-1])+1) % s->n_chan;
1121 if (nowmustbechan!=CR_CHAN(chanlist[i])) { // channel list isn't continous :-(
1122 rt_printk("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1123 dev->minor,i,CR_CHAN(chanlist[i]),
1124 nowmustbechan,CR_CHAN(chanlist[0]) );
1127 // well, this is next correct channel in list
1128 chansegment[i]=chanlist[i];
1131 // check whole chanlist
1132 for (i=0, segpos=0; i<n_chan; i++) {
1133 //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]));
1134 if (chanlist[i]!=chansegment[i%seglen]) {
1135 rt_printk("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1136 dev->minor,i,CR_CHAN(chansegment[i]),
1137 CR_RANGE(chansegment[i]),
1138 CR_AREF(chansegment[i]),
1139 CR_CHAN(chanlist[i%seglen]),
1140 CR_RANGE(chanlist[i%seglen]),
1141 CR_AREF(chansegment[i%seglen]));
1142 return 0; // chan/gain list is strange
1148 rt_printk("check_channel_list: seglen %d\n", seglen);
1152 static void setup_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist,
1153 unsigned int n_chan, unsigned int seglen)
1157 devpriv->act_chanlist_len=seglen;
1158 devpriv->act_chanlist_pos=0;
1160 for (i=0; i<seglen; i++) { // store range list to card
1161 devpriv->act_chanlist[i]=CR_CHAN(chanlist[i]);
1162 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase+PCL818_MUX); /* select channel */
1163 outb(CR_RANGE(chanlist[i]), dev->iobase+PCL818_RANGE); /* select gain */
1168 /* select channel interval to scan*/
1169 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen-1] << 4),
1170 dev->iobase+PCL818_MUX);
1174 ==============================================================================
1175 Check if board is switched to SE (1) or DIFF(0) mode
1177 static int check_single_ended(unsigned int port)
1179 if (inb(port+PCL818_STATUS)&0x20) { return 1; }
1184 ==============================================================================
1186 static int ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd) {
1188 int tmp,divisor1,divisor2;
1190 /* step 1: make sure trigger sources are trivially valid */
1193 cmd->start_src &= TRIG_NOW;
1194 if(!cmd->start_src || tmp!=cmd->start_src)err++;
1196 tmp=cmd->scan_begin_src;
1197 cmd->scan_begin_src &= TRIG_FOLLOW;
1198 if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++;
1200 tmp=cmd->convert_src;
1201 cmd->convert_src &= TRIG_TIMER|TRIG_EXT;
1202 if(!cmd->convert_src || tmp!=cmd->convert_src)err++;
1204 tmp=cmd->scan_end_src;
1205 cmd->scan_end_src &= TRIG_COUNT;
1206 if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++;
1209 cmd->stop_src &= TRIG_COUNT|TRIG_NONE;
1210 if(!cmd->stop_src || tmp!=cmd->stop_src)err++;
1216 /* step 2: make sure trigger sources are unique and mutually compatible */
1218 if(cmd->start_src!=TRIG_NOW) {
1219 cmd->start_src=TRIG_NOW;
1222 if(cmd->scan_begin_src!=TRIG_FOLLOW) {
1223 cmd->scan_begin_src=TRIG_FOLLOW;
1226 if(cmd->convert_src!=TRIG_TIMER &&
1227 cmd->convert_src!=TRIG_EXT) err++;
1229 if(cmd->scan_end_src!=TRIG_COUNT) {
1230 cmd->scan_end_src=TRIG_COUNT;
1234 if(cmd->stop_src!=TRIG_NONE &&
1235 cmd->stop_src!=TRIG_COUNT) err++;
1241 /* step 3: make sure arguments are trivially compatible */
1243 if(cmd->start_arg!=0){
1248 if(cmd->scan_begin_arg!=0){
1249 cmd->scan_begin_arg=0;
1253 if(cmd->convert_src==TRIG_TIMER){
1254 if(cmd->convert_arg<this_board->ns_min){
1255 cmd->convert_arg=this_board->ns_min;
1258 } else { /* TRIG_EXT */
1259 if(cmd->convert_arg!=0){
1265 if(!cmd->chanlist_len){
1266 cmd->chanlist_len=1;
1269 if(cmd->chanlist_len>s->n_chan){
1270 cmd->chanlist_len=s->n_chan;
1273 if(cmd->scan_end_arg!=cmd->chanlist_len){
1274 cmd->scan_end_arg=cmd->chanlist_len;
1277 if(cmd->stop_src==TRIG_COUNT){
1282 } else { /* TRIG_NONE */
1283 if(cmd->stop_arg!=0){
1293 /* step 4: fix up any arguments */
1295 if(cmd->convert_src==TRIG_TIMER){
1296 tmp=cmd->convert_arg;
1297 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,&divisor1,&divisor2,&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
1298 if(cmd->convert_arg<this_board->ns_min)
1299 cmd->convert_arg=this_board->ns_min;
1300 if(tmp!=cmd->convert_arg)err++;
1307 /* step 5: complain about special chanlist considerations */
1310 if (!check_channel_list(dev, s, cmd->chanlist,
1311 cmd->chanlist_len)) return 5; // incorrect channels list
1318 ==============================================================================
1320 static int ai_cmd(comedi_device *dev,comedi_subdevice *s) {
1321 comedi_cmd *cmd=&s->async->cmd;
1324 rt_printk("pcl818_ai_cmd()\n");
1325 devpriv->ai_n_chan=cmd->chanlist_len;
1326 devpriv->ai_chanlist=cmd->chanlist;
1327 devpriv->ai_flags=cmd->flags;
1328 devpriv->ai_data_len=s->async->prealloc_bufsz;
1329 devpriv->ai_data=s->async->prealloc_buf;
1330 devpriv->ai_timer1=0;
1331 devpriv->ai_timer2=0;
1333 if (cmd->stop_src==TRIG_COUNT) { devpriv->ai_scans=cmd->stop_arg; }
1334 else { devpriv->ai_scans=0; }
1336 if(cmd->scan_begin_src==TRIG_FOLLOW){ // mode 1, 3
1337 if (cmd->convert_src==TRIG_TIMER) { // mode 1
1338 devpriv->ai_timer1=cmd->convert_arg;
1339 retval = pcl818_ai_cmd_mode(1,dev,s);
1340 rt_printk("pcl818_ai_cmd() end\n");
1343 if (cmd->convert_src==TRIG_EXT) { // mode 3
1344 return pcl818_ai_cmd_mode(3,dev,s);
1354 ==============================================================================
1355 cancel any mode 1-4 AI
1357 static int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s)
1359 if (devpriv->irq_blocked>0) {
1360 rt_printk("pcl818_ai_cancel()\n");
1361 devpriv->irq_was_now_closed=devpriv->ai_mode;
1364 switch (devpriv->irq_was_now_closed) {
1366 case INT_TYPE_AI1_DMA_RTC:
1367 case INT_TYPE_AI3_DMA_RTC:
1368 set_rtc_irq_bit(0); // stop RTC
1369 del_timer(&devpriv->rtc_irq_timer);
1371 case INT_TYPE_AI1_DMA:
1372 case INT_TYPE_AI3_DMA:
1373 if ( devpriv->neverending_ai ) {
1374 /* wait for running dma transfer to end, do cleanup in interrupt */
1377 disable_dma(devpriv->dma);
1378 case INT_TYPE_AI1_INT:
1379 case INT_TYPE_AI3_INT:
1380 case INT_TYPE_AI1_FIFO:
1381 case INT_TYPE_AI3_FIFO:
1382 #ifdef PCL818_MODE13_AO
1383 case INT_TYPE_AO1_INT:
1384 case INT_TYPE_AO3_INT:
1386 outb(inb(dev->iobase+PCL818_CONTROL)& 0x73, dev->iobase+PCL818_CONTROL); /* Stop A/D */
1388 start_pacer(dev,-1,0,0);
1389 outb(0, dev->iobase+PCL818_AD_LO);
1390 inb(dev->iobase+PCL818_AD_LO);
1391 inb(dev->iobase+PCL818_AD_HI);
1392 outb(0, dev->iobase+PCL818_CLRINT); /* clear INT request */
1393 outb(0, dev->iobase+PCL818_CONTROL); /* Stop A/D */
1394 if (devpriv->usefifo) { // FIFO shutdown
1395 outb(0, dev->iobase + PCL818_FI_INTCLR);
1396 outb(0, dev->iobase + PCL818_FI_FLUSH);
1397 outb(0, dev->iobase + PCL818_FI_ENABLE);
1399 devpriv->irq_blocked=0;
1400 devpriv->last_int_sub=s;
1401 devpriv->neverending_ai=0;
1407 rt_printk("pcl818_ai_cancel() end\n");
1412 ==============================================================================
1415 static int pcl818_check(unsigned long iobase)
1417 outb(0x00, iobase + PCL818_MUX);
1419 if (inb(iobase + PCL818_MUX)!=0x00) return 1; //there isn't card
1420 outb(0x55, iobase + PCL818_MUX);
1422 if (inb(iobase + PCL818_MUX)!=0x55) return 1; //there isn't card
1423 outb(0x00, iobase + PCL818_MUX);
1425 outb(0x18, iobase + PCL818_CONTROL);
1427 if (inb(iobase + PCL818_CONTROL)!=0x18) return 1; //there isn't card
1428 return 0; // ok, card exist
1432 ==============================================================================
1433 reset whole PCL-818 cards
1435 static void pcl818_reset(comedi_device * dev)
1437 if (devpriv->usefifo) { // FIFO shutdown
1438 outb(0, dev->iobase + PCL818_FI_INTCLR);
1439 outb(0, dev->iobase + PCL818_FI_FLUSH);
1440 outb(0, dev->iobase + PCL818_FI_ENABLE);
1442 outb(0, dev->iobase + PCL818_DA_LO); // DAC=0V
1443 outb(0, dev->iobase + PCL818_DA_HI);
1445 outb(0, dev->iobase + PCL818_DO_HI); // DO=$0000
1446 outb(0, dev->iobase + PCL818_DO_LO);
1448 outb(0, dev->iobase + PCL818_CONTROL);
1449 outb(0, dev->iobase + PCL818_CNTENABLE);
1450 outb(0, dev->iobase + PCL818_MUX);
1451 outb(0, dev->iobase + PCL818_CLRINT);
1452 outb(0xb0, dev->iobase + PCL818_CTRCTL);/* Stop pacer */
1453 outb(0x70, dev->iobase + PCL818_CTRCTL);
1454 outb(0x30, dev->iobase + PCL818_CTRCTL);
1455 if(this_board->is_818){
1456 outb(0, dev->iobase + PCL818_RANGE);
1458 outb(0, dev->iobase + PCL718_DA2_LO);
1459 outb(0, dev->iobase + PCL718_DA2_HI);
1465 ==============================================================================
1466 Enable(1)/disable(0) periodic interrupts from RTC
1468 static int set_rtc_irq_bit(unsigned char bit)
1471 unsigned long flags;
1475 if (RTC_timer_lock>1) return 0;
1478 if (RTC_timer_lock<0) RTC_timer_lock=0;
1479 if (RTC_timer_lock>0) return 0;
1484 val = CMOS_READ(RTC_CONTROL);
1485 if (bit) { val |= RTC_PIE; }
1486 else { val &= ~RTC_PIE; }
1487 CMOS_WRITE(val, RTC_CONTROL);
1488 CMOS_READ(RTC_INTR_FLAGS);
1489 restore_flags(flags);
1494 ==============================================================================
1495 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1497 static void rtc_dropped_irq(unsigned long data)
1499 comedi_device *dev = (void *)data;
1500 unsigned long flags,tmp;
1502 switch(devpriv->int818_mode) {
1503 case INT_TYPE_AI1_DMA_RTC:
1504 case INT_TYPE_AI3_DMA_RTC:
1505 mod_timer(&devpriv->rtc_irq_timer, jiffies + HZ/devpriv->rtc_freq + 2*HZ/100);
1508 tmp=(CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1509 restore_flags(flags);
1516 ==============================================================================
1517 Set frequency of interrupts from RTC
1519 static int rtc_setfreq_irq(int freq)
1524 unsigned long flags;
1527 if (freq>8192) freq=8192;
1529 while (freq>(1<<tmp))
1536 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1538 CMOS_WRITE(val, RTC_FREQ_SELECT);
1539 restore_flags(flags);
1545 ==============================================================================
1546 Free any resources that we have claimed
1548 static void free_resources(comedi_device * dev)
1550 //rt_printk("free_resource()\n");
1552 pcl818_ai_cancel(dev, devpriv->sub_ai);
1554 if (devpriv->dma) free_dma(devpriv->dma);
1555 if (devpriv->dmabuf[0]) free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1556 if (devpriv->dmabuf[1]) free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1558 if (devpriv->rtc_irq) comedi_free_irq(devpriv->rtc_irq, dev);
1559 if ((devpriv->dma_rtc)&&(RTC_lock==1)) {
1560 if (devpriv->rtc_iobase)
1561 release_region(devpriv->rtc_iobase, devpriv->rtc_iosize);
1563 if (devpriv->dma_rtc)
1568 if (dev->irq) free_irq(dev->irq, dev);
1569 if (dev->iobase) release_region(dev->iobase, devpriv->io_range);
1570 //rt_printk("free_resource() end\n");
1574 ==============================================================================
1579 static int pcl818_attach(comedi_device * dev, comedi_devconfig * it)
1582 unsigned long iobase;
1583 unsigned int irq,dma;
1584 unsigned long pages;
1585 comedi_subdevice *s;
1588 if((ret=alloc_private(dev,sizeof(pcl818_private)))<0)
1589 return ret; /* Can't alloc mem */
1591 /* claim our I/O space */
1592 iobase = it->options[0];
1593 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1594 dev->minor, this_board->name, iobase);
1595 devpriv->io_range=this_board->io_range;
1596 if ((this_board->fifo)&&(it->options[2]==-1)) { // we've board with FIFO and we want to use FIFO
1597 devpriv->io_range=PCLx1xFIFO_RANGE;
1598 devpriv->usefifo = 1;
1600 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1601 rt_printk("I/O port conflict\n");
1607 if (pcl818_check(iobase)) {
1608 rt_printk(", I can't detect board. FAIL!\n");
1612 /* set up some name stuff */
1613 dev->board_name = this_board->name;
1616 if (this_board->IRQbits!=0) { /* board support IRQ */
1618 if (irq) {/* we want to use IRQ */
1619 if (((1<<irq)&this_board->IRQbits)==0) {
1620 rt_printk(", IRQ %u is out of allowed range, DISABLING IT",irq);
1621 irq=0; /* Bad IRQ */
1623 if (comedi_request_irq(irq, interrupt_pcl818, 0, "pcl818", dev)) {
1624 rt_printk(", unable to allocate IRQ %u, DISABLING IT", irq);
1625 irq=0; /* Can't use IRQ */
1627 rt_printk(", irq=%u", irq);
1634 if (irq) { devpriv->irq_free=1; } /* 1=we have allocated irq */
1635 else { devpriv->irq_free=0; }
1636 devpriv->irq_blocked=0; /* number of subdevice which use IRQ */
1637 devpriv->ai_mode=0; /* mode of irq */
1640 /* grab RTC for DMA operations */
1642 if (it->options[2]>0) { // we want to use DMA
1644 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "pcl818 (RTC)"))
1647 devpriv->rtc_iobase=RTC_PORT(0);
1648 devpriv->rtc_iosize=RTC_IO_EXTENT;
1650 if (!comedi_request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0, "pcl818 DMA (RTC)", dev)) {
1652 devpriv->rtc_irq=RTC_IRQ;
1653 rt_printk(", dma_irq=%u", devpriv->rtc_irq);
1657 if (devpriv->rtc_iobase) release_region(devpriv->rtc_iobase, devpriv->rtc_iosize);
1659 devpriv->rtc_iobase=0;
1660 devpriv->rtc_iosize=0;
1669 if ((devpriv->irq_free==0)&&(devpriv->dma_rtc==0)) goto no_dma; /* if we haven't IRQ, we can't use DMA */
1670 if (this_board->DMAbits!=0) { /* board support DMA */
1672 if (dma<1) goto no_dma; /* DMA disabled */
1673 if (((1<<dma)&this_board->DMAbits)==0) {
1674 rt_printk(", DMA is out of allowed range, FAIL!\n");
1675 return -EINVAL; /* Bad DMA */
1677 ret=request_dma(dma, "pcl818");
1679 rt_printk(", unable to allocate DMA %u, FAIL!\n",dma);
1680 return -EBUSY; /* DMA isn't free */
1683 rt_printk(", dma=%u", dma);
1684 pages=2; /* we need 16KB */
1685 devpriv->dmabuf[0]=__get_dma_pages(GFP_KERNEL, pages);
1686 if (!devpriv->dmabuf[0]) {
1687 rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1688 /* maybe experiment with try_to_free_pages() will help .... */
1689 return -EBUSY; /* no buffer :-( */
1691 devpriv->dmapages[0]=pages;
1692 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1693 devpriv->hwdmasize[0]=(1<<pages)*PAGE_SIZE;
1694 //rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE);
1695 if (devpriv->dma_rtc==0) { // we must do duble buff :-(
1696 devpriv->dmabuf[1]=__get_dma_pages(GFP_KERNEL, pages);
1697 if (!devpriv->dmabuf[1]) {
1698 rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1701 devpriv->dmapages[1]=pages;
1702 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1703 devpriv->hwdmasize[1]=(1<<pages)*PAGE_SIZE;
1709 if((ret=alloc_subdevices(dev, 4))<0) return ret;
1711 s = dev->subdevices + 0;
1712 if(!this_board->n_aichan_se){
1713 s->type = COMEDI_SUBD_UNUSED;
1715 dev->read_subdev = s;
1716 s->type = COMEDI_SUBD_AI;
1718 s->subdev_flags = SDF_READABLE;
1719 if (check_single_ended(dev->iobase)) {
1720 s->n_chan = this_board->n_aichan_se;
1721 s->subdev_flags|=SDF_COMMON|SDF_GROUND;
1722 printk(", %dchans S.E. DAC",s->n_chan);
1724 s->n_chan = this_board->n_aichan_diff;
1725 s->subdev_flags|=SDF_DIFF;
1726 printk(", %dchans DIFF DAC",s->n_chan);
1728 s->maxdata = this_board->ai_maxdata;
1729 s->len_chanlist = s->n_chan;
1730 s->range_table = this_board->ai_range_type;
1731 s->cancel=pcl818_ai_cancel;
1732 s->insn_read = pcl818_ai_insn_read;
1733 if ((irq)||(devpriv->dma_rtc)) {
1734 s->do_cmdtest=ai_cmdtest;
1737 if(this_board->is_818){
1738 if ((it->options[4]==1)||(it->options[4]==10))
1739 s->range_table=&range_pcl818l_h_ai; // secondary range list jumper selectable
1741 switch (it->options[4]) {
1742 case 0: s->range_table=&range_bipolar10; break;
1743 case 1: s->range_table=&range_bipolar5; break;
1744 case 2: s->range_table=&range_bipolar2_5; break;
1745 case 3: s->range_table=&range718_bipolar1; break;
1746 case 4: s->range_table=&range718_bipolar0_5; break;
1747 case 6: s->range_table=&range_unipolar10; break;
1748 case 7: s->range_table=&range_unipolar5; break;
1749 case 8: s->range_table=&range718_unipolar2; break;
1750 case 9: s->range_table=&range718_unipolar1; break;
1751 default: s->range_table=&range_unknown; break;
1756 s = dev->subdevices + 1;
1757 if(!this_board->n_aochan){
1758 s->type = COMEDI_SUBD_UNUSED;
1760 dev->write_subdev = s;
1761 s->type = COMEDI_SUBD_AO;
1762 s->subdev_flags = SDF_WRITABLE|SDF_GROUND;
1763 s->n_chan = this_board->n_aochan;
1764 s->maxdata = this_board->ao_maxdata;
1765 s->len_chanlist = this_board->n_aochan;
1766 s->range_table = this_board->ao_range_type;
1767 s->insn_read = pcl818_ao_insn_read;
1768 s->insn_write = pcl818_ao_insn_write;
1770 #ifdef PCL818_MODE13_AO
1772 s->trig[1] = pcl818_ao_mode1;
1773 s->trig[3] = pcl818_ao_mode3;
1777 if(this_board->is_818){
1778 if ((it->options[4]==1)||(it->options[4]==10))
1779 s->range_table=&range_unipolar10;
1780 if (it->options[4]==2)
1781 s->range_table=&range_unknown;
1783 if ((it->options[5]==1)||(it->options[5]==10))
1784 s->range_table=&range_unipolar10;
1785 if (it->options[5]==2)
1786 s->range_table=&range_unknown;
1790 s = dev->subdevices + 2;
1791 if(!this_board->n_dichan){
1792 s->type = COMEDI_SUBD_UNUSED;
1794 s->type = COMEDI_SUBD_DI;
1795 s->subdev_flags = SDF_READABLE;
1796 s->n_chan = this_board->n_dichan;
1798 s->len_chanlist = this_board->n_dichan;
1799 s->range_table = &range_digital;
1800 s->insn_bits = pcl818_di_insn_bits;
1803 s = dev->subdevices + 3;
1804 if(!this_board->n_dochan){
1805 s->type = COMEDI_SUBD_UNUSED;
1807 s->type = COMEDI_SUBD_DO;
1808 s->subdev_flags = SDF_WRITABLE;
1809 s->n_chan = this_board->n_dochan;
1811 s->len_chanlist = this_board->n_dochan;
1812 s->range_table = &range_digital;
1813 s->insn_bits = pcl818_do_insn_bits;
1816 /* select 1/10MHz oscilator */
1817 if ((it->options[3]==0)||(it->options[3]==10)) {
1818 devpriv->i8253_osc_base= 100;
1820 devpriv->i8253_osc_base=1000;
1823 /* max sampling speed */
1824 devpriv->ns_min=this_board->ns_min;
1826 if(!this_board->is_818){
1827 if ((it->options[6]==1)||(it->options[6]==100))
1828 devpriv->ns_min=10000; /* extended PCL718 to 100kHz DAC */
1840 ==============================================================================
1843 static int pcl818_detach(comedi_device * dev)
1845 // rt_printk("comedi%d: pcl818: remove\n", dev->minor);
1846 free_resources(dev);