4 Author: Michal Dobes <majkl@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 <majkl@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/ioport.h>
102 #include <linux/module.h>
103 #include <linux/mc146818rtc.h>
104 #include <linux/delay.h>
106 #include <linux/comedidev.h>
109 // #define PCL818_MODE13_AO 1
113 #define boardPCL818L 0
114 #define boardPCL818H 1
115 #define boardPCL818HD 2
116 #define boardPCL818HG 3
117 #define boardPCL818 4
118 #define boardPCL718 5
121 #define PCLx1x_RANGE 16
122 // IO space len if we use FIFO
123 #define PCLx1xFIFO_RANGE 32
125 // W: clear INT request
126 #define PCL818_CLRINT 8
127 // R: return status byte
128 #define PCL818_STATUS 8
129 // R: A/D high byte W: A/D range control
130 #define PCL818_RANGE 1
131 // R: next mux scan channel W: mux scan channel & range control pointer
133 // R/W: operation control register
134 #define PCL818_CONTROL 9
136 #define PCL818_CNTENABLE 10
138 // R: low byte of A/D W: soft A/D trigger
139 #define PCL818_AD_LO 0
140 // R: high byte of A/D W: A/D range control
141 #define PCL818_AD_HI 1
142 // W: D/A low&high byte
143 #define PCL818_DA_LO 4
144 #define PCL818_DA_HI 5
145 // R: low&high byte of DI
146 #define PCL818_DI_LO 3
147 #define PCL818_DI_HI 11
148 // W: low&high byte of DO
149 #define PCL818_DO_LO 3
150 #define PCL818_DO_HI 11
151 // W: PCL718 second D/A
152 #define PCL718_DA2_LO 6
153 #define PCL718_DA2_HI 7
155 #define PCL818_CTR0 12
156 #define PCL818_CTR1 13
157 #define PCL818_CTR2 14
158 // W: counter control
159 #define PCL818_CTRCTL 15
161 // W: fifo enable/disable
162 #define PCL818_FI_ENABLE 6
163 // W: fifo interrupt clear
164 #define PCL818_FI_INTCLR 20
165 // W: fifo interrupt clear
166 #define PCL818_FI_FLUSH 25
168 #define PCL818_FI_STATUS 25
169 // R: one record from FIFO
170 #define PCL818_FI_DATALO 23
171 #define PCL818_FI_DATAHI 23
173 // type of interrupt handler
174 #define INT_TYPE_AI1_INT 1
175 #define INT_TYPE_AI1_DMA 2
176 #define INT_TYPE_AI1_FIFO 3
177 #define INT_TYPE_AI3_INT 4
178 #define INT_TYPE_AI3_DMA 5
179 #define INT_TYPE_AI3_FIFO 6
180 #ifdef PCL818_MODE13_AO
181 #define INT_TYPE_AO1_INT 7
182 #define INT_TYPE_AO3_INT 8
184 #define INT_TYPE_AI1_DMA_RTC 9
185 #define INT_TYPE_AI3_DMA_RTC 10
189 #define RTC_IO_EXTENT 0x10
191 #define MAGIC_DMA_WORD 0x5a5a
193 static comedi_lrange range_pcl818h_ai = { 9, {
205 static comedi_lrange range_pcl818hg_ai = { 10, {
220 static comedi_lrange range_pcl818l_l_ai = { 4, {
227 static comedi_lrange range_pcl818l_h_ai = { 4, {
234 static comedi_lrange range718_bipolar1 = { 1, { BIP_RANGE(1), }};
235 static comedi_lrange range718_bipolar0_5 = { 1, { BIP_RANGE(0.5), }};
236 static comedi_lrange range718_unipolar2 = { 1, { UNI_RANGE(2), }};
237 static comedi_lrange range718_unipolar1 = { 1, { BIP_RANGE(1), }};
239 static int pcl818_attach(comedi_device *dev,comedi_devconfig *it);
240 static int pcl818_detach(comedi_device *dev);
242 static int RTC_lock = 0; /* RTC lock */
243 static int RTC_timer_lock = 0; /* RTC int lock */
246 char *name; // driver name
247 int n_ranges; // len of range list
248 int n_aichan_se; // num of A/D chans in single ended mode
249 int n_aichan_diff; // num of A/D chans in diferencial mode
250 unsigned int ns_min; // minimal alllowed delay between samples (in ns)
251 int n_aochan; // num of D/A chans
252 int n_dichan; // num of DI chans
253 int n_dochan; // num of DO chans
254 comedi_lrange *ai_range_type; // default A/D rangelist
255 comedi_lrange *ao_range_type; // dafault D/A rangelist
256 int io_range; // len of IO space
257 unsigned int IRQbits; // allowed interrupts
258 unsigned int DMAbits; // allowed DMA chans
259 int ai_maxdata; // maxdata for A/D
260 int ao_maxdata; // maxdata for D/A
261 int ai_chanlist; // allowed len of channel list A/D
262 int ao_chanlist; // allowed len of channel list D/A
263 unsigned char fifo; // 1=board has FIFO
267 static boardtype boardtypes[] =
269 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
270 0x0a, 0xfff, 0xfff, 1024, 1, 0, 1 },
271 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
272 0x0a, 0xfff, 0xfff, 1024, 1, 0, 1 },
273 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
274 0x0a, 0xfff, 0xfff, 1024, 1, 1, 1 },
275 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
276 0x0a, 0xfff, 0xfff, 1024, 1, 1, 1 },
277 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
278 0x0a, 0xfff, 0xfff, 1024, 2, 0, 1 },
279 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
280 0x0a, 0xfff, 0xfff, 1024, 2, 0, 0 },
282 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, &range_unipolar5, PCLx1x_RANGE, 0x00fc,
283 0x0a, 0xfff, 0xfff, 1024, 0, 0, 1 /* XXX ? */ },
286 #define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
288 static comedi_driver driver_pcl818={
289 driver_name: "pcl818",
291 attach: pcl818_attach,
292 detach: pcl818_detach,
293 board_name: boardtypes,
294 num_names: n_boardtypes,
295 offset: sizeof(boardtype),
297 COMEDI_INITCLEANUP(driver_pcl818);
301 int dma; // used DMA, 0=don't use DMA
302 int dma_rtc; // 1=RTC used with DMA, 0=no RTC alloc
304 unsigned int rtc_iobase; // RTC port region
305 unsigned int rtc_iosize;
306 unsigned int rtc_irq;
307 unsigned long dmabuf[2]; // pointers to begin of DMA buffers
308 unsigned int dmapages[2]; // len of DMA buffers in PAGE_SIZEs
309 unsigned int hwdmaptr[2]; // hardware address of DMA buffers
310 unsigned int hwdmasize[2]; // len of DMA buffers in Bytes
311 unsigned int dmasamplsize; // size in samples hwdmasize[0]/2
312 unsigned int last_top_dma; // DMA pointer in last RTC int
313 int next_dma_buf; // which DMA buffer will be used next round
314 long dma_runs_to_end;// how many we must permorm DMA transfer to end of record
315 unsigned long last_dma_run; // how many bytes we must transfer on last DMA page
316 unsigned char neverending_ai; // if=1, then we do neverending record (you must use cancel())
317 unsigned int ns_min; // manimal alllowed delay between samples (in us) for actual card
318 int i8253_osc_base; // 1/frequency of on board oscilator in ns
319 int irq_free; // 1=have allocated IRQ
320 int irq_blocked; // 1=IRQ now uses any subdev
321 int rtc_irq_blocked;// 1=we now do AI with DMA&RTC
322 int irq_was_now_closed;// when IRQ finish, there's stored int818_mode for last interrupt
323 int int818_mode; // who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma
324 comedi_subdevice *last_int_sub; // ptr to subdevice which now finish
325 int int13_act_scan; // how many scans we finished
326 int int13_act_chan; // actual position in actual scan
327 unsigned int act_chanlist[16];// MUX setting for actual AI operations
328 unsigned int act_chanlist_len;// how long is actual MUX list
329 unsigned int act_chanlist_pos;// actual position in MUX list
330 unsigned int buf_ptr; // data buffer ptr in samples
331 comedi_subdevice *sub_ai; // ptr to AI subdevice
332 unsigned char usefifo; // 1=use fifo
333 struct timer_list rtc_irq_timer;// timer for RTC sanity check
334 unsigned long rtc_freq; // RTC int freq
335 lsampl_t ao_readback[2];
339 static unsigned int muxonechan[] ={ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // used for gain list programming
340 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
342 #define devpriv ((pcl818_private *)dev->private)
343 #define this_board ((boardtype *)dev->board_ptr)
346 ==============================================================================
349 static int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, comedi_trig * it);
351 static int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s);
353 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2);
355 static int set_rtc_irq_bit(unsigned char bit);
357 static void rtc_dropped_irq(unsigned long data);
358 static int rtc_setfreq_irq(int freq);
362 ==============================================================================
363 ANALOG INPUT MODE0, 818 cards, slow version
365 static int pcl818_ai_insn_read(comedi_device *dev, comedi_subdevice *s,
366 comedi_insn *insn, lsampl_t *data)
371 /* software trigger, DMA and INT off */
372 outb(0, dev->iobase+PCL818_CONTROL);
375 outb(muxonechan[CR_CHAN(insn->chanspec)],
376 dev->iobase+PCL818_MUX);
379 outb(CR_RANGE(insn->chanspec),
380 dev->iobase+PCL818_RANGE);
382 for(n=0;n<insn->n;n++){
384 /* clear INT (conversion end) flag */
385 outb(0, dev->iobase+PCL818_CLRINT);
387 /* start conversion */
388 outb(0, dev->iobase+PCL818_AD_LO);
392 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
396 comedi_error(dev,"A/D insn timeout");
397 /* clear INT (conversion end) flag */
398 outb(0, dev->iobase+PCL818_CLRINT);
402 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
403 (inb(dev->iobase + PCL818_AD_LO) >> 4));
410 ==============================================================================
411 ANALOG OUTPUT MODE0, 818 cards
412 only one sample per call is supported
414 static int pcl818_ao_insn_read(comedi_device *dev, comedi_subdevice *s,
415 comedi_insn *insn, lsampl_t *data)
418 int chan = CR_CHAN(insn->chanspec);
420 for(n=0;n<insn->n;n++){
421 data[n] = devpriv->ao_readback[chan];
427 static int pcl818_ao_insn_write(comedi_device *dev, comedi_subdevice *s,
428 comedi_insn *insn, lsampl_t *data)
431 int chan = CR_CHAN(insn->chanspec);
433 for(n=0;n<insn->n;n++){
434 devpriv->ao_readback[chan] = data[n];
435 outb((data[n] & 0x000f) << 4, dev->iobase+
436 (chan)?PCL718_DA2_LO:PCL818_DA_LO);
437 outb((data[n] & 0x0ff0) >> 4, dev->iobase+
438 (chan)?PCL718_DA2_HI:PCL818_DA_HI);
445 ==============================================================================
446 DIGITAL INPUT MODE0, 818 cards
448 only one sample per call is supported
450 static int pcl818_di_insn_bits(comedi_device *dev, comedi_subdevice *s,
451 comedi_insn *insn, lsampl_t *data)
453 if(insn->n!=2)return -EINVAL;
455 data[1] = inb(dev->iobase + PCL818_DI_LO) |
456 (inb(dev->iobase + PCL818_DI_HI) << 8);
462 ==============================================================================
463 DIGITAL OUTPUT MODE0, 818 cards
465 only one sample per call is supported
467 static int pcl818_do_insn_bits(comedi_device *dev, comedi_subdevice *s,
468 comedi_insn *insn, lsampl_t *data)
470 if(insn->n!=2)return -EINVAL;
472 s->state &= ~data[0];
473 s->state |= (data[0]&data[1]);
475 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
476 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
484 ==============================================================================
485 analog input interrupt mode 1 & 3, 818 cards
486 one sample per interrupt version
488 static void interrupt_pcl818_ai_mode13_int(int irq, void *d, struct pt_regs *regs)
490 comedi_device *dev = d;
491 comedi_subdevice *s = dev->subdevices + 0;
493 int timeout=50; /* wait max 50us */
496 if (inb(dev->iobase + PCL818_STATUS) & 0x10) goto conv_finish;
499 outb(0,dev->iobase+PCL818_STATUS); /* clear INT request */
500 comedi_error(dev,"A/D mode1/3 IRQ without DRDY!");
501 pcl818_ai_cancel(dev,s);
502 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
503 comedi_event(dev, s, s->async->events);
507 low=inb(dev->iobase + PCL818_AD_LO);
508 *(sampl_t *)(s->async->data+devpriv->buf_ptr)=((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4)); // get one sample
509 devpriv->buf_ptr+=sizeof(sampl_t);
510 outb(0,dev->iobase+PCL818_CLRINT); /* clear INT request */
512 if ((low & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
513 rt_printk("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",(low & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos]);
514 pcl818_ai_cancel(dev,s);
515 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
516 comedi_event(dev, s, s->async->events);
519 s->async->buf_int_ptr+=sizeof(sampl_t);
520 s->async->buf_int_count+=sizeof(sampl_t);
522 s->async->cur_chan++;
523 if (s->async->cur_chan>=s->async->cmd.chanlist_len){
524 s->async->cur_chan=0;
525 s->async->events |= COMEDI_CB_BLOCK;
527 devpriv->int13_act_scan--;
530 if (s->async->buf_int_ptr>=s->async->data_len) { /* buffer rollover */
531 s->async->buf_int_ptr=0;
534 s->async->events |= COMEDI_CB_EOBUF;
537 if (!devpriv->neverending_ai){
538 if ( devpriv->int13_act_scan == 0 ) { /* all data sampled */
539 pcl818_ai_cancel(dev,s);
540 s->async->events |= COMEDI_CB_EOA;
544 comedi_event(dev, s, s->async->events);
548 ==============================================================================
549 analog input dma mode 1 & 3, 818 cards
551 static void interrupt_pcl818_ai_mode13_dma(int irq, void *d, struct pt_regs *regs)
553 comedi_device *dev = d;
554 comedi_subdevice *s = dev->subdevices + 0;
559 disable_dma(devpriv->dma);
560 devpriv->next_dma_buf=1-devpriv->next_dma_buf;
561 if ((devpriv->dma_runs_to_end)>-1) { // switch dma bufs
562 set_dma_mode(devpriv->dma, DMA_MODE_READ);
563 flags=claim_dma_lock();
564 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
565 if (devpriv->dma_runs_to_end) { set_dma_count(devpriv->dma, devpriv->hwdmasize[devpriv->next_dma_buf]); }
566 else { set_dma_count(devpriv->dma, devpriv->last_dma_run); }
567 release_dma_lock(flags);
568 enable_dma(devpriv->dma);
571 devpriv->dma_runs_to_end--;
572 outb(0,dev->iobase+PCL818_CLRINT); /* clear INT request */
573 ptr=(sampl_t *)devpriv->dmabuf[1-devpriv->next_dma_buf];
575 len=devpriv->hwdmasize[0] >> 1;
578 for (i=0;i<len;i++) {
579 if ((ptr[bufptr] & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
580 rt_printk("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",(ptr[bufptr] & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos]);
581 pcl818_ai_cancel(dev,s);
582 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
583 comedi_event(dev, s, s->async->events);
587 *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=
588 ptr[bufptr++] >> 4; // get one sample
591 s->async->buf_int_ptr+=sizeof(sampl_t);
592 s->async->buf_int_count+=sizeof(sampl_t);
593 devpriv->act_chanlist_pos++;
595 s->async->cur_chan++;
596 if(s->async->cur_chan>=s->async->cmd.chanlist_len){
597 s->async->cur_chan=0;
600 if (s->async->buf_int_ptr>=s->async->data_len) { /* buffer rollover */
601 s->async->buf_int_ptr=0;
603 s->async->events |= COMEDI_CB_EOBUF;
606 if (!devpriv->neverending_ai)
607 if ( devpriv->int13_act_scan == 0 ) { /* all data sampled */
608 pcl818_ai_cancel(dev,s);
609 s->async->events |= COMEDI_CB_EOA;
610 comedi_event(dev, s, s->async->events);
611 // printk("done int ai13 dma\n");
616 if (len>0) comedi_event(dev, s, s->async->events);
620 ==============================================================================
621 analog input dma mode 1 & 3 over RTC, 818 cards
623 static void interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d, struct pt_regs *regs)
625 comedi_device *dev = d;
626 comedi_subdevice *s = dev->subdevices + 0;
628 unsigned int top1,top2,i,bufptr;
630 sampl_t *dmabuf=(sampl_t *)devpriv->dmabuf[0];
633 switch(devpriv->int818_mode) {
634 case INT_TYPE_AI1_DMA_RTC:
635 case INT_TYPE_AI3_DMA_RTC:
636 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
637 mod_timer(&devpriv->rtc_irq_timer, jiffies + HZ/devpriv->rtc_freq + 2*HZ/100);
639 for (i=0; i<10; i++) {
640 top1=get_dma_residue(devpriv->dma);
641 top2=get_dma_residue(devpriv->dma);
642 if (top1==top2) break;
645 if (top1!=top2) return;
646 top1=devpriv->hwdmasize[0]-top1; // where is now DMA in buffer
648 ofs_dats=top1-devpriv->last_top_dma; // new samples from last call
649 if (ofs_dats<0) ofs_dats=(devpriv->dmasamplsize)+ofs_dats;
650 if (!ofs_dats) return; // exit=no new samples from last call
652 i=devpriv->last_top_dma-1;
653 i&=(devpriv->dmasamplsize-1);
655 if (dmabuf[i]!=MAGIC_DMA_WORD) { // DMA overflow!
656 comedi_error(dev,"A/D mode1/3 DMA buffer overflow!");
657 //rt_printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize);
658 pcl818_ai_cancel(dev,s);
659 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
660 comedi_event(dev, s, s->async->events);
663 //rt_printk("r %ld ",ofs_dats);
665 bufptr=devpriv->last_top_dma;
667 for (i=0; i<ofs_dats; i++) {
668 if ((dmabuf[bufptr] & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
669 rt_printk("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",(dmabuf[bufptr] & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos]);
670 pcl818_ai_cancel(dev,s);
671 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
672 comedi_event(dev, s, s->async->events);
676 *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=
677 dmabuf[bufptr++] >> 4; // get one sample
679 bufptr&=(devpriv->dmasamplsize-1);
681 s->async->buf_int_ptr+=sizeof(sampl_t);
682 s->async->buf_int_count+=sizeof(sampl_t);
684 s->async->cur_chan++;
685 if(s->async->cur_chan>=s->async->cmd.chanlist_len){
686 s->async->cur_chan++;
687 devpriv->int13_act_scan--;
690 if (s->async->buf_int_ptr>=s->async->data_len) { /* buffer rollover */
691 s->async->buf_int_ptr=0;
693 s->async->events |= COMEDI_CB_EOBUF;
696 if (!devpriv->neverending_ai)
697 if ( devpriv->int13_act_scan == 0 ) { /* all data sampled */
698 pcl818_ai_cancel(dev,s);
699 s->async->events |= COMEDI_CB_EOA;
700 comedi_event(dev, s, s->async->events);
701 //printk("done int ai13 dma\n");
706 devpriv->last_top_dma=bufptr;
708 bufptr&=(devpriv->dmasamplsize-1);
709 dmabuf[bufptr]=MAGIC_DMA_WORD;
710 comedi_event(dev, s, s->async->events);
719 ==============================================================================
720 analog input interrupt mode 1 & 3, 818HD/HG cards
722 static void interrupt_pcl818_ai_mode13_fifo(int irq, void *d, struct pt_regs *regs)
724 comedi_device *dev = d;
725 comedi_subdevice *s = dev->subdevices + 0;
728 outb(0, dev->iobase + PCL818_FI_INTCLR); // clear fifo int request
730 lo=inb(dev->iobase + PCL818_FI_STATUS);
733 comedi_error(dev,"A/D mode1/3 FIFO overflow!");
734 pcl818_ai_cancel(dev,s);
735 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
736 comedi_event(dev, s, s->async->events);
741 comedi_error(dev,"A/D mode1/3 FIFO interrupt without data!");
742 pcl818_ai_cancel(dev,s);
743 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
744 comedi_event(dev, s, s->async->events);
748 if (lo&2) { len=512; }
751 for (i=0;i<len;i++) {
752 lo=inb(dev->iobase + PCL818_FI_DATALO);
753 if ((lo & 0xf)!=devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
754 rt_printk("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",(lo & 0xf),devpriv->act_chanlist[devpriv->act_chanlist_pos]);
755 pcl818_ai_cancel(dev,s);
756 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
757 comedi_event(dev, s, s->async->events);
761 *(sampl_t *)(s->async->data+s->async->buf_int_ptr)=
762 (lo >> 4)|(inb(dev->iobase + PCL818_FI_DATAHI) << 4); // get one sample
764 s->async->buf_int_ptr+=sizeof(sampl_t);
765 s->async->buf_int_count+=sizeof(sampl_t);
767 s->async->cur_chan++;
768 if(s->async->cur_chan>=s->async->cmd.chanlist_len){
769 s->async->cur_chan = 0;
770 devpriv->int13_act_scan--;
773 if (s->async->buf_int_ptr>=s->async->data_len) { /* buffer rollover */
774 s->async->buf_int_ptr=0;
776 s->async->events |= COMEDI_CB_EOBUF;
779 if (!devpriv->neverending_ai)
780 if ( devpriv->int13_act_scan == 0 ) { /* all data sampled */
781 pcl818_ai_cancel(dev,s);
782 s->async->events |= COMEDI_CB_EOA;
783 comedi_event(dev, s, s->async->events);
788 if (len>0) comedi_event(dev, s, s->async->events);
792 ==============================================================================
795 static void interrupt_pcl818(int irq, void *d, struct pt_regs *regs)
797 comedi_device *dev = d;
801 comedi_error(dev, "premature interrupt");
807 switch (devpriv->int818_mode) {
808 case INT_TYPE_AI1_DMA:
809 case INT_TYPE_AI3_DMA:
810 interrupt_pcl818_ai_mode13_dma(irq, d, regs);
812 case INT_TYPE_AI1_INT:
813 case INT_TYPE_AI3_INT:
814 interrupt_pcl818_ai_mode13_int(irq, d, regs);
816 case INT_TYPE_AI1_FIFO:
817 case INT_TYPE_AI3_FIFO:
818 interrupt_pcl818_ai_mode13_fifo(irq, d, regs);
820 #ifdef PCL818_MODE13_AO
821 case INT_TYPE_AO1_INT:
822 case INT_TYPE_AO3_INT:
823 interrupt_pcl818_ao_mode13_int(irq, d, regs);
828 outb(0,dev->iobase+PCL818_CLRINT); /* clear INT request */
830 if ((!dev->irq)|(!devpriv->irq_free)|(!devpriv->irq_blocked)|(!devpriv->int818_mode)) {
831 if (devpriv->irq_was_now_closed) {
832 devpriv->irq_was_now_closed=0;
833 // comedi_error(dev,"last IRQ..");
836 comedi_error(dev,"bad IRQ!");
840 comedi_error(dev,"IRQ from unknow source!");
844 ==============================================================================
845 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
848 static void pcl818_ai_mode13dma_int(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
853 bytes=devpriv->hwdmasize[0];
854 if (!devpriv->neverending_ai) {
855 bytes=it->n_chan*it->n*sizeof(sampl_t); // how many
856 devpriv->dma_runs_to_end=bytes / devpriv->hwdmasize[0]; // how many DMA pages we must fiil
857 devpriv->last_dma_run=bytes % devpriv->hwdmasize[0]; //on last dma transfer must be moved
858 devpriv->dma_runs_to_end--;
859 if (devpriv->dma_runs_to_end>=0) bytes=devpriv->hwdmasize[0];
860 //rt_printk("%d %d %d\n",devpriv->dma_runs_to_end,devpriv->last_dma_run,bytes);
863 devpriv->next_dma_buf=0;
864 set_dma_mode(devpriv->dma, DMA_MODE_READ);
865 flags=claim_dma_lock();
866 clear_dma_ff(devpriv->dma);
867 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
868 set_dma_count(devpriv->dma, bytes);
869 release_dma_lock(flags);
870 enable_dma(devpriv->dma);
873 devpriv->int818_mode=INT_TYPE_AI1_DMA;
874 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
876 devpriv->int818_mode=INT_TYPE_AI3_DMA;
877 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
882 ==============================================================================
883 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
885 static void pcl818_ai_mode13dma_rtc(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
890 set_dma_mode(devpriv->dma, DMA_MODE_READ|DMA_AUTOINIT);
891 flags=claim_dma_lock();
892 clear_dma_ff(devpriv->dma);
893 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
894 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
895 release_dma_lock(flags);
896 enable_dma(devpriv->dma);
897 devpriv->last_top_dma=0; //devpriv->hwdmasize[0];
898 pole=(sampl_t *)devpriv->dmabuf[0];
899 devpriv->dmasamplsize=devpriv->hwdmasize[0]/2;
900 pole[devpriv->dmasamplsize-1]=MAGIC_DMA_WORD;
901 devpriv->rtc_freq=rtc_setfreq_irq(2048);
902 devpriv->rtc_irq_timer.expires=jiffies + HZ/devpriv->rtc_freq + 2*HZ/100;
903 devpriv->rtc_irq_timer.data=(unsigned long)dev;
904 devpriv->rtc_irq_timer.function=rtc_dropped_irq;
906 add_timer(&devpriv->rtc_irq_timer);
909 devpriv->int818_mode=INT_TYPE_AI1_DMA_RTC;
910 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
912 devpriv->int818_mode=INT_TYPE_AI3_DMA_RTC;
913 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
918 ==============================================================================
919 ANALOG INPUT MODE 1 or 3, 818 cards
921 static int pcl818_ai_mode13(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
923 int divisor1, divisor2;
925 if ((!dev->irq)&&(!devpriv->dma_rtc)) {
926 comedi_error(dev,"IRQ not defined!");
930 if (devpriv->irq_blocked)
933 start_pacer(dev, -1, 0, 0); // stop pacer
935 if (!check_and_setup_channel_list(dev, s, it)) return -EINVAL;
938 devpriv->int13_act_scan=it->n;
939 devpriv->int13_act_chan=0;
940 devpriv->irq_blocked=1;
941 devpriv->irq_was_now_closed=0;
942 devpriv->neverending_ai=0;
943 devpriv->act_chanlist_pos=0;
946 if ((it->n==0)||(it->n==-1)) devpriv->neverending_ai=1; //well, user want neverending
949 if (it->trigvar<devpriv->ns_min) it->trigvar=devpriv->ns_min;
950 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,&divisor1,&divisor2,&it->trigvar,TRIG_ROUND_NEAREST);
951 if (divisor1==1) { /* PCL718/818 crash if any divisor is set to 1 */
961 outb(0 , dev->iobase + PCL818_CNTENABLE); /* enable pacer */
963 switch (devpriv->dma>0) {
966 if (devpriv->dma_rtc==0) { pcl818_ai_mode13dma_int(mode, dev, s, it); }
967 else { pcl818_ai_mode13dma_rtc(mode, dev, s, it); }
970 // rt_printk("IRQ\n");
972 devpriv->int818_mode=INT_TYPE_AI1_INT;
973 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
975 devpriv->int818_mode=INT_TYPE_AI3_INT;
976 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
980 outb(1, dev->iobase + PCL818_FI_ENABLE); // enable FIFO
982 devpriv->int818_mode=INT_TYPE_AI1_FIFO;
983 outb(0x03, dev->iobase + PCL818_CONTROL); /* Pacer */
985 devpriv->int818_mode=INT_TYPE_AI3_FIFO;
986 outb(0x02, dev->iobase + PCL818_CONTROL);
991 start_pacer(dev, mode, divisor1, divisor2);
993 switch(devpriv->int818_mode) {
994 case INT_TYPE_AI1_DMA_RTC:
995 case INT_TYPE_AI3_DMA_RTC:
996 set_rtc_irq_bit(1); /* start RTC */
1004 ==============================================================================
1005 ANALOG INPUT MODE 1, 818 cards
1007 static int pcl818_ai_mode1(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1009 return pcl818_ai_mode13(1, dev, s, it);
1013 ==============================================================================
1014 ANALOG INPUT MODE 3, 818 cards
1016 static int pcl818_ai_mode3(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1018 return pcl818_ai_mode13(3, dev, s, it);
1022 ==============================================================================
1023 ANALOG OUTPUT MODE 1 or 3, 818 cards
1025 #ifdef PCL818_MODE13_AO
1026 static int pcl818_ao_mode13(int mode, comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1028 int divisor1, divisor2;
1032 comedi_error(dev,"IRQ not defined!");
1036 if (devpriv->irq_blocked)
1039 start_pacer(dev, -1, 0, 0); // stop pacer
1041 devpriv->int13_act_scan=it->n;
1042 devpriv->int13_act_chan=0;
1043 devpriv->irq_blocked=1;
1044 devpriv->irq_was_now_closed=0;
1045 devpriv->neverending_ai=0;
1046 devpriv->act_chanlist_pos=0;
1050 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,&divisor1,&divisor2,&it->trigvar,TRIG_ROUND_NEAREST);
1051 if (divisor1==1) { /* PCL818 crash if any divisor is set to 1 */
1061 outb(0 , dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1063 devpriv->int818_mode=INT_TYPE_AO1_INT;
1064 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1066 devpriv->int818_mode=INT_TYPE_AO3_INT;
1067 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1070 start_pacer(dev, mode, divisor1, divisor2);
1076 ==============================================================================
1077 ANALOG OUTPUT MODE 1, 818 cards
1079 static int pcl818_ao_mode1(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1081 return pcl818_ao_mode13(1, dev, s, it);
1085 ==============================================================================
1086 ANALOG OUTPUT MODE 3, 818 cards
1088 static int pcl818_ao_mode3(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1090 return pcl818_ao_mode13(3, dev, s, it);
1096 ==============================================================================
1097 Start/stop pacer onboard pacer
1100 static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2)
1102 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1103 outb(0x74, dev->iobase + PCL818_CTRCTL);
1104 outb(0x30, dev->iobase + PCL818_CTRCTL);
1108 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1109 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1110 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1111 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1116 ==============================================================================
1117 Check if channel list from user is builded correctly
1118 If it's ok, then program scan/gain logic
1120 static int check_and_setup_channel_list(comedi_device * dev, comedi_subdevice * s, comedi_trig * it)
1122 unsigned int chansegment[16];
1123 unsigned int i, nowmustbechan, seglen, segpos;
1125 /* correct channel and range number check itself comedi/range.c */
1127 comedi_error(dev,"range/channel list is empty!");
1131 if (it->n_chan > 1) {
1132 // first channel is everytime ok
1133 chansegment[0]=it->chanlist[0];
1134 // build part of chanlist
1135 for (i=1, seglen=1; i<it->n_chan; i++, seglen++) {
1136 // rt_printk("%d. %d %d\n",i,CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));
1137 // we detect loop, this must by finish
1138 if (it->chanlist[0]==it->chanlist[i]) break;
1139 nowmustbechan=(CR_CHAN(chansegment[i-1])+1) % s->n_chan;
1140 // channel list isn't continous :-(
1141 if (nowmustbechan!=CR_CHAN(it->chanlist[i])) {
1142 rt_printk("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1143 dev->minor,i,CR_CHAN(it->chanlist[i]),
1144 nowmustbechan,CR_CHAN(it->chanlist[0]) );
1147 // well, this is next correct channel in list
1148 chansegment[i]=it->chanlist[i];
1151 // check whole chanlist
1152 for (i=0, segpos=0; i<it->n_chan; i++) {
1153 //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]));
1154 if (it->chanlist[i]!=chansegment[i%seglen]) {
1155 rt_printk("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1156 dev->minor,i,CR_CHAN(chansegment[i]),
1157 CR_RANGE(chansegment[i]),
1158 CR_AREF(chansegment[i]),
1159 CR_CHAN(it->chanlist[i%seglen]),
1160 CR_RANGE(it->chanlist[i%seglen]),
1161 CR_AREF(chansegment[i%seglen]));
1162 return 0; // chan/gain list is strange
1169 devpriv->act_chanlist_len=seglen;
1170 devpriv->act_chanlist_pos=0;
1172 for (i=0; i<seglen; i++) { // store range list to card
1173 devpriv->act_chanlist[i]=CR_CHAN(it->chanlist[i]);
1174 outb(muxonechan[CR_CHAN(it->chanlist[i])], dev->iobase+PCL818_MUX); /* select channel */
1175 outb(CR_RANGE(it->chanlist[i]), dev->iobase+PCL818_RANGE); /* select gain */
1180 /* select channel interval to sca n*/
1181 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen-1] << 4),
1182 dev->iobase+PCL818_MUX);
1183 // printk(" MUX %x\n",devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen-1] << 4));
1185 // we can serve this with MUX logic
1191 ==============================================================================
1192 Check if board is switched to SE (1) or DIFF(0) mode
1194 static int check_single_ended(unsigned int port)
1196 if (inb(port+PCL818_STATUS)&0x20) { return 1; }
1201 ==============================================================================
1202 cancel any mode 1-4 AI
1204 static int pcl818_ai_cancel(comedi_device * dev, comedi_subdevice * s)
1206 if (devpriv->irq_blocked>0) {
1207 // rt_printk("pcl818_ai_cancel()\n");
1208 switch (devpriv->int818_mode) {
1209 case INT_TYPE_AI1_DMA_RTC:
1210 case INT_TYPE_AI3_DMA_RTC:
1211 set_rtc_irq_bit(0); // stop RTC
1212 del_timer(&devpriv->rtc_irq_timer);
1213 case INT_TYPE_AI1_DMA:
1214 case INT_TYPE_AI3_DMA:
1215 disable_dma(devpriv->dma);
1216 case INT_TYPE_AI1_INT:
1217 case INT_TYPE_AI3_INT:
1218 case INT_TYPE_AI1_FIFO:
1219 case INT_TYPE_AI3_FIFO:
1220 #ifdef PCL818_MODE13_AO
1221 case INT_TYPE_AO1_INT:
1222 case INT_TYPE_AO3_INT:
1224 outb(inb(dev->iobase+PCL818_CONTROL)& 0x73, dev->iobase+PCL818_CONTROL); /* Stop A/D */
1226 outb(0, dev->iobase+PCL818_CONTROL); /* Stop A/D */
1227 outb(0xb4, dev->iobase + PCL818_CTRCTL);/* Stop pacer */
1228 outb(0x74, dev->iobase + PCL818_CTRCTL);
1229 outb(0, dev->iobase+PCL818_AD_LO);
1230 inb(dev->iobase+PCL818_AD_LO);
1231 inb(dev->iobase+PCL818_AD_HI);
1232 outb(0, dev->iobase+PCL818_CLRINT); /* clear INT request */
1233 outb(0, dev->iobase+PCL818_CONTROL); /* Stop A/D */
1234 if (devpriv->usefifo) { // FIFO shutdown
1235 outb(0, dev->iobase + PCL818_FI_INTCLR);
1236 outb(0, dev->iobase + PCL818_FI_FLUSH);
1237 outb(0, dev->iobase + PCL818_FI_ENABLE);
1239 devpriv->irq_blocked=0;
1240 devpriv->irq_was_now_closed=devpriv->int818_mode;
1241 devpriv->int818_mode=0;
1242 devpriv->last_int_sub=s;
1247 //rt_printk("pcl818_ai_cancel() end\n");
1252 ==============================================================================
1255 static int pcl818_check(int iobase)
1257 outb(0x00, iobase + PCL818_MUX);
1259 if (inb(iobase + PCL818_MUX)!=0x00) return 1; //there isn't card
1260 outb(0x55, iobase + PCL818_MUX);
1262 if (inb(iobase + PCL818_MUX)!=0x55) return 1; //there isn't card
1263 outb(0x00, iobase + PCL818_MUX);
1265 outb(0x18, iobase + PCL818_CONTROL);
1267 if (inb(iobase + PCL818_CONTROL)!=0x18) return 1; //there isn't card
1268 return 0; // ok, card exist
1272 ==============================================================================
1273 reset whole PCL-818 cards
1275 static void pcl818_reset(comedi_device * dev)
1277 if (devpriv->usefifo) { // FIFO shutdown
1278 outb(0, dev->iobase + PCL818_FI_INTCLR);
1279 outb(0, dev->iobase + PCL818_FI_FLUSH);
1280 outb(0, dev->iobase + PCL818_FI_ENABLE);
1282 outb(0, dev->iobase + PCL818_DA_LO); // DAC=0V
1283 outb(0, dev->iobase + PCL818_DA_HI);
1285 outb(0, dev->iobase + PCL818_DO_HI); // DO=$0000
1286 outb(0, dev->iobase + PCL818_DO_LO);
1288 outb(0, dev->iobase + PCL818_CONTROL);
1289 outb(0, dev->iobase + PCL818_CNTENABLE);
1290 outb(0, dev->iobase + PCL818_MUX);
1291 outb(0, dev->iobase + PCL818_CLRINT);
1292 outb(0xb0, dev->iobase + PCL818_CTRCTL);/* Stop pacer */
1293 outb(0x70, dev->iobase + PCL818_CTRCTL);
1294 outb(0x30, dev->iobase + PCL818_CTRCTL);
1295 if(this_board->is_818){
1296 outb(0, dev->iobase + PCL818_RANGE);
1298 outb(0, dev->iobase + PCL718_DA2_LO);
1299 outb(0, dev->iobase + PCL718_DA2_HI);
1304 ==============================================================================
1305 Enable(1)/disable(0) periodic interrupts from RTC
1307 static int set_rtc_irq_bit(unsigned char bit)
1310 unsigned long flags;
1314 if (RTC_timer_lock>1) return 0;
1317 if (RTC_timer_lock<0) RTC_timer_lock=0;
1318 if (RTC_timer_lock>0) return 0;
1323 val = CMOS_READ(RTC_CONTROL);
1324 if (bit) { val |= RTC_PIE; }
1325 else { val &= ~RTC_PIE; }
1326 CMOS_WRITE(val, RTC_CONTROL);
1327 CMOS_READ(RTC_INTR_FLAGS);
1328 restore_flags(flags);
1333 ==============================================================================
1334 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1337 static void rtc_dropped_irq(unsigned long data)
1339 comedi_device *dev = (void *)data;
1340 unsigned long flags,tmp;
1342 switch(devpriv->int818_mode) {
1343 case INT_TYPE_AI1_DMA_RTC:
1344 case INT_TYPE_AI3_DMA_RTC:
1345 mod_timer(&devpriv->rtc_irq_timer, jiffies + HZ/devpriv->rtc_freq + 2*HZ/100);
1348 tmp=(CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1349 restore_flags(flags);
1356 ==============================================================================
1357 Set frequency of interrupts from RTC
1359 static int rtc_setfreq_irq(int freq)
1364 unsigned long flags;
1367 if (freq>8192) freq=8192;
1369 while (freq>(1<<tmp))
1376 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1378 CMOS_WRITE(val, RTC_FREQ_SELECT);
1379 restore_flags(flags);
1385 ==============================================================================
1386 Free any resources that we have claimed
1388 static void free_resources(comedi_device * dev)
1390 //rt_printk("free_resource()\n");
1392 pcl818_ai_cancel(dev, devpriv->sub_ai);
1394 if (devpriv->dma) free_dma(devpriv->dma);
1395 if (devpriv->dmabuf[0]) free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1396 if (devpriv->dmabuf[1]) free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1397 if (devpriv->rtc_irq) comedi_free_irq(devpriv->rtc_irq, dev);
1398 if ((devpriv->dma_rtc)&&(RTC_lock==1)) {
1399 if (devpriv->rtc_iobase)
1400 release_region(devpriv->rtc_iobase, devpriv->rtc_iosize);
1402 if (devpriv->dma_rtc)
1406 if (dev->irq) free_irq(dev->irq, dev);
1407 if (dev->iobase) release_region(dev->iobase, devpriv->io_range);
1408 //rt_printk("free_resource() end\n");
1412 ==============================================================================
1417 static int pcl818_attach(comedi_device * dev, comedi_devconfig * it)
1422 unsigned long pages;
1423 comedi_subdevice *s;
1426 if((ret=alloc_private(dev,sizeof(pcl818_private)))<0)
1427 return ret; /* Can't alloc mem */
1429 /* claim our I/O space */
1430 iobase = it->options[0];
1431 printk("comedi%d: pcl818: board=%s, ioport=0x%03x",
1432 dev->minor, this_board->name, iobase);
1433 devpriv->io_range=this_board->io_range;
1434 if ((this_board->fifo)&&(it->options[2]==-1)) { // we've board with FIFO and we want to use FIFO
1435 devpriv->io_range=PCLx1xFIFO_RANGE;
1436 devpriv->usefifo = 1;
1438 if (check_region(iobase, this_board->io_range) < 0) {
1439 rt_printk("I/O port conflict\n");
1443 request_region(iobase, devpriv->io_range, "pcl818");
1446 if (pcl818_check(iobase)) {
1447 rt_printk(", I can't detect board. FAIL!\n");
1451 /* set up some name stuff */
1452 dev->board_name = this_board->name;
1455 if (this_board->IRQbits!=0) { /* board support IRQ */
1457 if (irq>0) {/* we want to use IRQ */
1458 if (((1<<irq)&this_board->IRQbits)==0) {
1459 rt_printk(", IRQ %d is out of allowed range, DISABLING IT",irq);
1460 irq=0; /* Bad IRQ */
1462 if (comedi_request_irq(irq, interrupt_pcl818, 0, "pcl818", dev)) {
1463 rt_printk(", unable to allocate IRQ %d, DISABLING IT", irq);
1464 irq=0; /* Can't use IRQ */
1466 rt_printk(", irq=%d", irq);
1473 if (irq) { devpriv->irq_free=1; } /* 1=we have allocated irq */
1474 else { devpriv->irq_free=0; }
1475 devpriv->irq_blocked=0; /* number of subdevice which use IRQ */
1476 devpriv->int818_mode=0; /* mode of irq */
1478 /* grab RTC for DMA operations */
1480 if (it->options[2]>0) { // we want to use DMA
1482 if (check_region(RTC_PORT(0), RTC_IO_EXTENT) < 0) goto no_rtc;
1483 request_region(RTC_PORT(0), RTC_IO_EXTENT, "pcl818 (RTC)");
1485 devpriv->rtc_iobase=RTC_PORT(0);
1486 devpriv->rtc_iosize=RTC_IO_EXTENT;
1488 if (!comedi_request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0, "pcl818 DMA (RTC)", dev)) {
1490 devpriv->rtc_irq=RTC_IRQ;
1491 rt_printk(", dma_irq=%d", devpriv->rtc_irq);
1495 if (devpriv->rtc_iobase) release_region(devpriv->rtc_iobase, devpriv->rtc_iosize);
1497 devpriv->rtc_iobase=0;
1498 devpriv->rtc_iosize=0;
1506 if ((devpriv->irq_free==0)&&(devpriv->dma_rtc==0)) goto no_dma; /* if we haven't IRQ, we can't use DMA */
1507 if (this_board->DMAbits!=0) { /* board support DMA */
1509 if (dma<1) goto no_dma; /* DMA disabled */
1510 if (((1<<dma)&this_board->DMAbits)==0) {
1511 rt_printk(", DMA is out of allowed range, FAIL!\n");
1512 return -EINVAL; /* Bad DMA */
1514 ret=request_dma(dma, "pcl818");
1516 rt_printk(", unable to allocate DMA %d, FAIL!\n",dma);
1517 return -EBUSY; /* DMA isn't free */
1520 rt_printk(", dma=%d", dma);
1521 pages=2; /* we need 16KB */
1522 devpriv->dmabuf[0]=__get_dma_pages(GFP_KERNEL, pages);
1523 if (!devpriv->dmabuf[0]) {
1524 rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1525 /* maybe experiment with try_to_free_pages() will help .... */
1526 return -EBUSY; /* no buffer :-( */
1528 devpriv->dmapages[0]=pages;
1529 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1530 devpriv->hwdmasize[0]=(1<<pages)*PAGE_SIZE;
1531 //rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE);
1532 if (devpriv->dma_rtc==0) { // we must do duble buff :-(
1533 devpriv->dmabuf[1]=__get_dma_pages(GFP_KERNEL, pages);
1534 if (!devpriv->dmabuf[1]) {
1535 rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1538 devpriv->dmapages[1]=pages;
1539 devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
1540 devpriv->hwdmasize[1]=(1<<pages)*PAGE_SIZE;
1546 dev->n_subdevices = 4;
1547 if((ret=alloc_subdevices(dev))<0) return ret;
1549 s = dev->subdevices + 0;
1550 if(!this_board->n_aichan_se){
1551 s->type = COMEDI_SUBD_UNUSED;
1553 dev->read_subdev = s;
1554 s->type = COMEDI_SUBD_AI;
1556 s->subdev_flags = SDF_READABLE;
1557 if (check_single_ended(dev->iobase)) {
1558 s->n_chan = this_board->n_aichan_se;
1559 s->subdev_flags|=SDF_COMMON|SDF_GROUND;
1560 printk(", %dchans S.E. DAC",s->n_chan);
1562 s->n_chan = this_board->n_aichan_diff;
1563 s->subdev_flags|=SDF_DIFF;
1564 printk(", %dchans DIFF DAC",s->n_chan);
1566 s->maxdata = this_board->ai_maxdata;
1567 s->len_chanlist = this_board->ai_chanlist;
1568 s->range_table = this_board->ai_range_type;
1569 s->cancel=pcl818_ai_cancel;
1570 s->insn_read = pcl818_ai_insn_read;
1571 //if ((irq)||(devpriv->dma_rtc)) {
1572 //s->trig[1] = pcl818_ai_mode1;
1573 //s->trig[3] = pcl818_ai_mode3;
1575 if(this_board->is_818){
1576 if ((it->options[4]==1)||(it->options[4]==10))
1577 s->range_table=&range_pcl818l_h_ai; // secondary range list jumper selectable
1579 switch (it->options[4]) {
1580 case 0: s->range_table=&range_bipolar10; break;
1581 case 1: s->range_table=&range_bipolar5; break;
1582 case 2: s->range_table=&range_bipolar2_5; break;
1583 case 3: s->range_table=&range718_bipolar1; break;
1584 case 4: s->range_table=&range718_bipolar0_5; break;
1585 case 6: s->range_table=&range_unipolar10; break;
1586 case 7: s->range_table=&range_unipolar5; break;
1587 case 8: s->range_table=&range718_unipolar2; break;
1588 case 9: s->range_table=&range718_unipolar1; break;
1589 default: s->range_table=&range_unknown; break;
1594 s = dev->subdevices + 1;
1595 if(!this_board->n_aochan){
1596 s->type = COMEDI_SUBD_UNUSED;
1598 dev->write_subdev = s;
1599 s->type = COMEDI_SUBD_AO;
1600 s->subdev_flags = SDF_WRITABLE|SDF_GROUND|SDF_RT;
1601 s->n_chan = this_board->n_aochan;
1602 s->maxdata = this_board->ao_maxdata;
1603 s->len_chanlist = this_board->ao_chanlist;
1604 s->range_table = this_board->ao_range_type;
1605 s->insn_read = pcl818_ao_insn_read;
1606 s->insn_write = pcl818_ao_insn_write;
1608 #ifdef PCL818_MODE13_AO
1610 s->trig[1] = pcl818_ao_mode1;
1611 s->trig[3] = pcl818_ao_mode3;
1615 if(this_board->is_818){
1616 if ((it->options[4]==1)||(it->options[4]==10))
1617 s->range_table=&range_unipolar10;
1618 if (it->options[4]==2)
1619 s->range_table=&range_unknown;
1621 if ((it->options[5]==1)||(it->options[5]==10))
1622 s->range_table=&range_unipolar10;
1623 if (it->options[5]==2)
1624 s->range_table=&range_unknown;
1628 s = dev->subdevices + 2;
1629 if(!this_board->n_dichan){
1630 s->type = COMEDI_SUBD_UNUSED;
1632 s->type = COMEDI_SUBD_DI;
1633 s->subdev_flags = SDF_READABLE|SDF_RT;
1634 s->n_chan = this_board->n_dichan;
1636 s->len_chanlist = this_board->n_dichan;
1637 s->range_table = &range_digital;
1638 s->insn_bits = pcl818_di_insn_bits;
1641 s = dev->subdevices + 3;
1642 if(!this_board->n_dochan){
1643 s->type = COMEDI_SUBD_UNUSED;
1645 s->type = COMEDI_SUBD_DO;
1646 s->subdev_flags = SDF_WRITABLE|SDF_RT;
1647 s->n_chan = this_board->n_dochan;
1649 s->len_chanlist = this_board->n_dochan;
1650 s->range_table = &range_digital;
1651 s->insn_bits = pcl818_do_insn_bits;
1654 /* select 1/10MHz oscilator */
1655 if ((it->options[3]==0)||(it->options[3]==10)) {
1656 devpriv->i8253_osc_base= 100;
1658 devpriv->i8253_osc_base=1000;
1661 /* max sampling speed */
1662 devpriv->ns_min=this_board->ns_min;
1664 if(!this_board->is_818){
1665 if ((it->options[6]==1)||(it->options[6]==100))
1666 devpriv->ns_min=10000; /* extended PCL718 to 100kHz DAC */
1678 ==============================================================================
1681 static int pcl818_detach(comedi_device * dev)
1683 // rt_printk("comedi%d: pcl818: remove\n", dev->minor);
1684 free_resources(dev);