2 comedi/drivers/pcl818.c
4 Author: Michal Dobes <dobes@tesnet.cz>
6 hardware driver for Advantech cards:
7 card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8 driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718
12 Description: Advantech PCL-818 cards, PCL-718
13 Author: Michal Dobes <dobes@tesnet.cz>
14 Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15 PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
19 All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20 Differences are only at maximal sample speed, range list and FIFO
22 The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23 only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24 PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25 but this code is untested.
26 A word or two about DMA. Driver support DMA operations at two ways:
27 1) DMA uses two buffers and after one is filled then is generated
28 INT and DMA restart with second buffer. With this mode I'm unable run
29 more that 80Ksamples/secs without data dropouts on K6/233.
30 2) DMA uses one buffer and run in autoinit mode and the data are
31 from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32 This mode is used if the interrupt 8 is available for allocation.
33 If not, then first DMA mode is used. With this I can run at
34 full speed one card (100ksamples/secs) or two cards with
35 60ksamples/secs each (more is problem on account of ISA limitations).
36 To use this mode you must have compiled kernel with disabled
37 "Enhanced Real Time Clock Support".
38 Maybe you can have problems if you use xntpd or similar.
39 If you've data dropouts with DMA mode 2 then:
41 b) switch text mode console to fb.
45 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
46 [2] - DMA (0=disable, 1, 3)
47 [3] - 0, 10=10MHz clock for 8254
48 1= 1MHz clock for 8254
49 [4] - 0, 5=A/D input -5V.. +5V
50 1, 10=A/D input -10V..+10V
51 [5] - 0, 5=D/A output 0-5V (internal reference -5V)
52 1, 10=D/A output 0-10V (internal reference -10V)
53 2 =D/A output unknow (external reference)
55 Options for PCL-818, PCL-818H:
57 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
58 [2] - DMA (0=disable, 1, 3)
59 [3] - 0, 10=10MHz clock for 8254
60 1= 1MHz clock for 8254
61 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
62 1, 10=D/A output 0-10V (internal reference -10V)
63 2 =D/A output unknow (external reference)
65 Options for PCL-818HD, PCL-818HG:
67 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
68 [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA,
69 1=use DMA ch 1, 3=use DMA ch 3)
70 [3] - 0, 10=10MHz clock for 8254
71 1= 1MHz clock for 8254
72 [4] - 0, 5=D/A output 0-5V (internal reference -5V)
73 1, 10=D/A output 0-10V (internal reference -10V)
74 2 =D/A output unknow (external reference)
78 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
79 [2] - DMA (0=disable, 1, 3)
80 [3] - 0, 10=10MHz clock for 8254
81 1= 1MHz clock for 8254
82 [4] - 0=A/D Range is +/-10V
87 5= user defined bipolar
92 10= user defined unipolar
93 [5] - 0, 5=D/A outputs 0-5V (internal reference -5V)
94 1, 10=D/A outputs 0-10V (internal reference -10V)
95 2=D/A outputs unknow (external reference)
96 [6] - 0, 60=max 60kHz A/D sampling
97 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
101 #include "../comedidev.h"
103 #include <linux/ioport.h>
104 #include <linux/mc146818rtc.h>
105 #include <linux/delay.h>
110 // #define PCL818_MODE13_AO 1
114 #define boardPCL818L 0
115 #define boardPCL818H 1
116 #define boardPCL818HD 2
117 #define boardPCL818HG 3
118 #define boardPCL818 4
119 #define boardPCL718 5
122 #define PCLx1x_RANGE 16
123 // IO space len if we use FIFO
124 #define PCLx1xFIFO_RANGE 32
126 // W: clear INT request
127 #define PCL818_CLRINT 8
128 // R: return status byte
129 #define PCL818_STATUS 8
130 // R: A/D high byte W: A/D range control
131 #define PCL818_RANGE 1
132 // R: next mux scan channel W: mux scan channel & range control pointer
134 // R/W: operation control register
135 #define PCL818_CONTROL 9
137 #define PCL818_CNTENABLE 10
139 // R: low byte of A/D W: soft A/D trigger
140 #define PCL818_AD_LO 0
141 // R: high byte of A/D W: A/D range control
142 #define PCL818_AD_HI 1
143 // W: D/A low&high byte
144 #define PCL818_DA_LO 4
145 #define PCL818_DA_HI 5
146 // R: low&high byte of DI
147 #define PCL818_DI_LO 3
148 #define PCL818_DI_HI 11
149 // W: low&high byte of DO
150 #define PCL818_DO_LO 3
151 #define PCL818_DO_HI 11
152 // W: PCL718 second D/A
153 #define PCL718_DA2_LO 6
154 #define PCL718_DA2_HI 7
156 #define PCL818_CTR0 12
157 #define PCL818_CTR1 13
158 #define PCL818_CTR2 14
159 // W: counter control
160 #define PCL818_CTRCTL 15
162 // W: fifo enable/disable
163 #define PCL818_FI_ENABLE 6
164 // W: fifo interrupt clear
165 #define PCL818_FI_INTCLR 20
166 // W: fifo interrupt clear
167 #define PCL818_FI_FLUSH 25
169 #define PCL818_FI_STATUS 25
170 // R: one record from FIFO
171 #define PCL818_FI_DATALO 23
172 #define PCL818_FI_DATAHI 23
174 // type of interrupt handler
175 #define INT_TYPE_AI1_INT 1
176 #define INT_TYPE_AI1_DMA 2
177 #define INT_TYPE_AI1_FIFO 3
178 #define INT_TYPE_AI3_INT 4
179 #define INT_TYPE_AI3_DMA 5
180 #define INT_TYPE_AI3_FIFO 6
181 #ifdef PCL818_MODE13_AO
182 #define INT_TYPE_AO1_INT 7
183 #define INT_TYPE_AO3_INT 8
188 #define INT_TYPE_AI1_DMA_RTC 9
189 #define INT_TYPE_AI3_DMA_RTC 10
192 #define RTC_IO_EXTENT 0x10
195 #define MAGIC_DMA_WORD 0x5a5a
197 static const struct comedi_lrange range_pcl818h_ai = { 9, {
210 static const struct comedi_lrange range_pcl818hg_ai = { 10, {
226 static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
234 static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
242 static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
243 static const struct comedi_lrange range718_bipolar0_5 = { 1, {BIP_RANGE(0.5),} };
244 static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
245 static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
247 static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * it);
248 static int pcl818_detach(struct comedi_device * dev);
251 static int RTC_lock = 0; /* RTC lock */
252 static int RTC_timer_lock = 0; /* RTC int lock */
255 struct pcl818_board {
257 const char *name; // driver name
258 int n_ranges; // len of range list
259 int n_aichan_se; // num of A/D chans in single ended mode
260 int n_aichan_diff; // num of A/D chans in diferencial mode
261 unsigned int ns_min; // minimal alllowed delay between samples (in ns)
262 int n_aochan; // num of D/A chans
263 int n_dichan; // num of DI chans
264 int n_dochan; // num of DO chans
265 const struct comedi_lrange *ai_range_type; // default A/D rangelist
266 const struct comedi_lrange *ao_range_type; // default D/A rangelist
267 unsigned int io_range; // len of IO space
268 unsigned int IRQbits; // allowed interrupts
269 unsigned int DMAbits; // allowed DMA chans
270 int ai_maxdata; // maxdata for A/D
271 int ao_maxdata; // maxdata for D/A
272 unsigned char fifo; // 1=board has FIFO
277 static const struct pcl818_board boardtypes[] = {
278 {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
279 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
280 0x0a, 0xfff, 0xfff, 0, 1},
281 {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
282 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
283 0x0a, 0xfff, 0xfff, 0, 1},
284 {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
285 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
286 0x0a, 0xfff, 0xfff, 1, 1},
287 {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
288 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
289 0x0a, 0xfff, 0xfff, 1, 1},
290 {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
291 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
292 0x0a, 0xfff, 0xfff, 0, 1},
293 {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
294 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
295 0x0a, 0xfff, 0xfff, 0, 0},
297 {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
298 &range_unipolar5, PCLx1x_RANGE, 0x00fc,
299 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
302 #define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
304 static struct comedi_driver driver_pcl818 = {
305 driver_name:"pcl818",
307 attach:pcl818_attach,
308 detach:pcl818_detach,
309 board_name:&boardtypes[0].name,
310 num_names:n_boardtypes,
311 offset:sizeof(struct pcl818_board),
314 COMEDI_INITCLEANUP(driver_pcl818);
316 struct pcl818_private {
318 unsigned int dma; // used DMA, 0=don't use DMA
319 int dma_rtc; // 1=RTC used with DMA, 0=no RTC alloc
320 unsigned int io_range;
322 unsigned long rtc_iobase; // RTC port region
323 unsigned int rtc_iosize;
324 unsigned int rtc_irq;
325 struct timer_list rtc_irq_timer; // timer for RTC sanity check
326 unsigned long rtc_freq; // RTC int freq
327 int rtc_irq_blocked; // 1=we now do AI with DMA&RTC
329 unsigned long dmabuf[2]; // pointers to begin of DMA buffers
330 unsigned int dmapages[2]; // len of DMA buffers in PAGE_SIZEs
331 unsigned int hwdmaptr[2]; // hardware address of DMA buffers
332 unsigned int hwdmasize[2]; // len of DMA buffers in Bytes
333 unsigned int dmasamplsize; // size in samples hwdmasize[0]/2
334 unsigned int last_top_dma; // DMA pointer in last RTC int
335 int next_dma_buf; // which DMA buffer will be used next round
336 long dma_runs_to_end; // how many we must permorm DMA transfer to end of record
337 unsigned long last_dma_run; // how many bytes we must transfer on last DMA page
338 unsigned char neverending_ai; // if=1, then we do neverending record (you must use cancel())
339 unsigned int ns_min; // manimal alllowed delay between samples (in us) for actual card
340 int i8253_osc_base; // 1/frequency of on board oscilator in ns
341 int irq_free; // 1=have allocated IRQ
342 int irq_blocked; // 1=IRQ now uses any subdev
343 int irq_was_now_closed; // when IRQ finish, there's stored int818_mode for last interrupt
344 int ai_mode; // who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma
345 struct comedi_subdevice *last_int_sub; // ptr to subdevice which now finish
346 int ai_act_scan; // how many scans we finished
347 int ai_act_chan; // actual position in actual scan
348 unsigned int act_chanlist[16]; // MUX setting for actual AI operations
349 unsigned int act_chanlist_len; // how long is actual MUX list
350 unsigned int act_chanlist_pos; // actual position in MUX list
351 unsigned int ai_scans; // len of scanlist
352 unsigned int ai_n_chan; // how many channels is measured
353 unsigned int *ai_chanlist; // actaul chanlist
354 unsigned int ai_flags; // flaglist
355 unsigned int ai_data_len; // len of data buffer
356 short *ai_data; // data buffer
357 unsigned int ai_timer1; // timers
358 unsigned int ai_timer2;
359 struct comedi_subdevice *sub_ai; // ptr to AI subdevice
360 unsigned char usefifo; // 1=use fifo
361 unsigned int ao_readback[2];
365 static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // used for gain list programming
366 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
369 #define devpriv ((struct pcl818_private *)dev->private)
370 #define this_board ((const struct pcl818_board *)dev->board_ptr)
373 ==============================================================================
375 static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
376 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen);
377 static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
378 unsigned int *chanlist, unsigned int n_chan);
380 static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
381 static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
382 unsigned int divisor2);
385 static int set_rtc_irq_bit(unsigned char bit);
386 static void rtc_dropped_irq(unsigned long data);
387 static int rtc_setfreq_irq(int freq);
391 ==============================================================================
392 ANALOG INPUT MODE0, 818 cards, slow version
394 static int pcl818_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
395 struct comedi_insn * insn, unsigned int * data)
400 /* software trigger, DMA and INT off */
401 outb(0, dev->iobase + PCL818_CONTROL);
404 outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
407 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
409 for (n = 0; n < insn->n; n++) {
411 /* clear INT (conversion end) flag */
412 outb(0, dev->iobase + PCL818_CLRINT);
414 /* start conversion */
415 outb(0, dev->iobase + PCL818_AD_LO);
419 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
423 comedi_error(dev, "A/D insn timeout");
424 /* clear INT (conversion end) flag */
425 outb(0, dev->iobase + PCL818_CLRINT);
429 data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
430 (inb(dev->iobase + PCL818_AD_LO) >> 4));
437 ==============================================================================
438 ANALOG OUTPUT MODE0, 818 cards
439 only one sample per call is supported
441 static int pcl818_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
442 struct comedi_insn * insn, unsigned int * data)
445 int chan = CR_CHAN(insn->chanspec);
447 for (n = 0; n < insn->n; n++) {
448 data[n] = devpriv->ao_readback[chan];
454 static int pcl818_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
455 struct comedi_insn * insn, unsigned int * data)
458 int chan = CR_CHAN(insn->chanspec);
460 for (n = 0; n < insn->n; n++) {
461 devpriv->ao_readback[chan] = data[n];
462 outb((data[n] & 0x000f) << 4, dev->iobase +
463 (chan) ? PCL718_DA2_LO : PCL818_DA_LO);
464 outb((data[n] & 0x0ff0) >> 4, dev->iobase +
465 (chan) ? PCL718_DA2_HI : PCL818_DA_HI);
472 ==============================================================================
473 DIGITAL INPUT MODE0, 818 cards
475 only one sample per call is supported
477 static int pcl818_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
478 struct comedi_insn * insn, unsigned int * data)
483 data[1] = inb(dev->iobase + PCL818_DI_LO) |
484 (inb(dev->iobase + PCL818_DI_HI) << 8);
490 ==============================================================================
491 DIGITAL OUTPUT MODE0, 818 cards
493 only one sample per call is supported
495 static int pcl818_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
496 struct comedi_insn * insn, unsigned int * data)
501 s->state &= ~data[0];
502 s->state |= (data[0] & data[1]);
504 outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
505 outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
513 ==============================================================================
514 analog input interrupt mode 1 & 3, 818 cards
515 one sample per interrupt version
517 static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
519 struct comedi_device *dev = d;
520 struct comedi_subdevice *s = dev->subdevices + 0;
522 int timeout = 50; /* wait max 50us */
525 if (inb(dev->iobase + PCL818_STATUS) & 0x10)
529 outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
530 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
531 pcl818_ai_cancel(dev, s);
532 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
533 comedi_event(dev, s);
537 low = inb(dev->iobase + PCL818_AD_LO);
538 comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); // get one sample
539 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
541 if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
543 ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
545 devpriv->act_chanlist[devpriv->act_chanlist_pos]);
546 pcl818_ai_cancel(dev, s);
547 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
548 comedi_event(dev, s);
551 if (s->async->cur_chan == 0) {
553 devpriv->ai_act_scan--;
556 if (!devpriv->neverending_ai) {
557 if (devpriv->ai_act_scan == 0) { /* all data sampled */
558 pcl818_ai_cancel(dev, s);
559 s->async->events |= COMEDI_CB_EOA;
562 comedi_event(dev, s);
567 ==============================================================================
568 analog input dma mode 1 & 3, 818 cards
570 static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
572 struct comedi_device *dev = d;
573 struct comedi_subdevice *s = dev->subdevices + 0;
578 disable_dma(devpriv->dma);
579 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
580 if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { // switch dma bufs
581 set_dma_mode(devpriv->dma, DMA_MODE_READ);
582 flags = claim_dma_lock();
583 set_dma_addr(devpriv->dma,
584 devpriv->hwdmaptr[devpriv->next_dma_buf]);
585 if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
586 set_dma_count(devpriv->dma,
587 devpriv->hwdmasize[devpriv->next_dma_buf]);
589 set_dma_count(devpriv->dma, devpriv->last_dma_run);
591 release_dma_lock(flags);
592 enable_dma(devpriv->dma);
594 rt_printk("comedi: A/D mode1/3 IRQ \n");
596 devpriv->dma_runs_to_end--;
597 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
598 ptr = (short *) devpriv->dmabuf[1 - devpriv->next_dma_buf];
600 len = devpriv->hwdmasize[0] >> 1;
603 for (i = 0; i < len; i++) {
604 if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
606 ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
608 devpriv->act_chanlist[devpriv->
610 devpriv->act_chanlist_pos);
611 pcl818_ai_cancel(dev, s);
612 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
613 comedi_event(dev, s);
617 comedi_buf_put(s->async, ptr[bufptr++] >> 4); // get one sample
619 devpriv->act_chanlist_pos++;
620 if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) {
621 devpriv->ai_act_scan--;
622 devpriv->act_chanlist_pos = 0;
625 if (!devpriv->neverending_ai)
626 if (devpriv->ai_act_scan == 0) { /* all data sampled */
627 pcl818_ai_cancel(dev, s);
628 s->async->events |= COMEDI_CB_EOA;
629 comedi_event(dev, s);
630 // printk("done int ai13 dma\n");
636 comedi_event(dev, s);
642 ==============================================================================
643 analog input dma mode 1 & 3 over RTC, 818 cards
645 static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
647 struct comedi_device *dev = d;
648 struct comedi_subdevice *s = dev->subdevices + 0;
650 unsigned int top1, top2, i, bufptr;
652 short *dmabuf = (short *) devpriv->dmabuf[0];
655 switch (devpriv->ai_mode) {
656 case INT_TYPE_AI1_DMA_RTC:
657 case INT_TYPE_AI3_DMA_RTC:
658 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
659 mod_timer(&devpriv->rtc_irq_timer,
660 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
662 for (i = 0; i < 10; i++) {
663 top1 = get_dma_residue(devpriv->dma);
664 top2 = get_dma_residue(devpriv->dma);
671 top1 = devpriv->hwdmasize[0] - top1; // where is now DMA in buffer
673 ofs_dats = top1 - devpriv->last_top_dma; // new samples from last call
675 ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
677 return IRQ_HANDLED; // exit=no new samples from last call
679 i = devpriv->last_top_dma - 1;
680 i &= (devpriv->dmasamplsize - 1);
682 if (dmabuf[i] != MAGIC_DMA_WORD) { // DMA overflow!
683 comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
684 //rt_printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize);
685 pcl818_ai_cancel(dev, s);
686 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
687 comedi_event(dev, s);
690 //rt_printk("r %ld ",ofs_dats);
692 bufptr = devpriv->last_top_dma;
694 for (i = 0; i < ofs_dats; i++) {
695 if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
697 ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
698 (dmabuf[bufptr] & 0xf),
699 devpriv->act_chanlist[devpriv->
701 pcl818_ai_cancel(dev, s);
703 COMEDI_CB_EOA | COMEDI_CB_ERROR;
704 comedi_event(dev, s);
708 comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); // get one sample
709 bufptr &= (devpriv->dmasamplsize - 1);
711 if (s->async->cur_chan == 0) {
712 devpriv->ai_act_scan--;
715 if (!devpriv->neverending_ai)
716 if (devpriv->ai_act_scan == 0) { /* all data sampled */
717 pcl818_ai_cancel(dev, s);
718 s->async->events |= COMEDI_CB_EOA;
719 comedi_event(dev, s);
720 //printk("done int ai13 dma\n");
725 devpriv->last_top_dma = bufptr;
727 bufptr &= (devpriv->dmasamplsize - 1);
728 dmabuf[bufptr] = MAGIC_DMA_WORD;
729 comedi_event(dev, s);
740 ==============================================================================
741 analog input interrupt mode 1 & 3, 818HD/HG cards
743 static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
745 struct comedi_device *dev = d;
746 struct comedi_subdevice *s = dev->subdevices + 0;
749 outb(0, dev->iobase + PCL818_FI_INTCLR); // clear fifo int request
751 lo = inb(dev->iobase + PCL818_FI_STATUS);
754 comedi_error(dev, "A/D mode1/3 FIFO overflow!");
755 pcl818_ai_cancel(dev, s);
756 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
757 comedi_event(dev, s);
762 comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
763 pcl818_ai_cancel(dev, s);
764 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
765 comedi_event(dev, s);
775 for (i = 0; i < len; i++) {
776 lo = inb(dev->iobase + PCL818_FI_DATALO);
777 if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { // dropout!
779 ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
781 devpriv->act_chanlist[devpriv->
783 pcl818_ai_cancel(dev, s);
784 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
785 comedi_event(dev, s);
789 comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); // get one sample
791 if (s->async->cur_chan == 0) {
792 devpriv->ai_act_scan--;
795 if (!devpriv->neverending_ai)
796 if (devpriv->ai_act_scan == 0) { /* all data sampled */
797 pcl818_ai_cancel(dev, s);
798 s->async->events |= COMEDI_CB_EOA;
799 comedi_event(dev, s);
805 comedi_event(dev, s);
810 ==============================================================================
813 static irqreturn_t interrupt_pcl818(int irq, void *d PT_REGS_ARG)
815 struct comedi_device *dev = d;
817 if (!dev->attached) {
818 comedi_error(dev, "premature interrupt");
823 switch (devpriv->ai_mode) {
824 case INT_TYPE_AI1_DMA:
825 case INT_TYPE_AI3_DMA:
826 return interrupt_pcl818_ai_mode13_dma(irq, d);
827 case INT_TYPE_AI1_INT:
828 case INT_TYPE_AI3_INT:
829 return interrupt_pcl818_ai_mode13_int(irq, d);
830 case INT_TYPE_AI1_FIFO:
831 case INT_TYPE_AI3_FIFO:
832 return interrupt_pcl818_ai_mode13_fifo(irq, d);
833 #ifdef PCL818_MODE13_AO
834 case INT_TYPE_AO1_INT:
835 case INT_TYPE_AO3_INT:
836 return interrupt_pcl818_ao_mode13_int(irq, d);
842 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
844 if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
845 || (!devpriv->ai_mode)) {
846 if (devpriv->irq_was_now_closed) {
847 if (devpriv->neverending_ai &&
848 (devpriv->ai_mode == INT_TYPE_AI1_DMA
849 || devpriv->ai_mode ==
851 /* we had neverending ai but ai_cancel() has been called
852 the cleanup from ai_cancel() has been delayed until know
853 because the card doesn't seem to like being reprogrammed
854 while a DMA transfer is in progress
856 struct comedi_subdevice *s = dev->subdevices + 0;
857 devpriv->ai_mode = devpriv->irq_was_now_closed;
858 devpriv->irq_was_now_closed = 0;
859 devpriv->neverending_ai = 0;
860 pcl818_ai_cancel(dev, s);
862 devpriv->irq_was_now_closed = 0;
865 comedi_error(dev, "bad IRQ!");
869 comedi_error(dev, "IRQ from unknow source!");
874 ==============================================================================
875 ANALOG INPUT MODE 1 or 3 DMA , 818 cards
877 static void pcl818_ai_mode13dma_int(int mode, struct comedi_device * dev,
878 struct comedi_subdevice * s)
883 rt_printk("mode13dma_int, mode: %d\n", mode);
884 disable_dma(devpriv->dma); // disable dma
885 bytes = devpriv->hwdmasize[0];
886 if (!devpriv->neverending_ai) {
887 bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); // how many
888 devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; // how many DMA pages we must fiil
889 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; //on last dma transfer must be moved
890 devpriv->dma_runs_to_end--;
891 if (devpriv->dma_runs_to_end >= 0)
892 bytes = devpriv->hwdmasize[0];
895 devpriv->next_dma_buf = 0;
896 set_dma_mode(devpriv->dma, DMA_MODE_READ);
897 flags = claim_dma_lock();
898 clear_dma_ff(devpriv->dma);
899 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
900 set_dma_count(devpriv->dma, bytes);
901 release_dma_lock(flags);
902 enable_dma(devpriv->dma);
905 devpriv->ai_mode = INT_TYPE_AI1_DMA;
906 outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
908 devpriv->ai_mode = INT_TYPE_AI3_DMA;
909 outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
915 ==============================================================================
916 ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
918 static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device * dev,
919 struct comedi_subdevice * s)
924 set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
925 flags = claim_dma_lock();
926 clear_dma_ff(devpriv->dma);
927 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
928 set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
929 release_dma_lock(flags);
930 enable_dma(devpriv->dma);
931 devpriv->last_top_dma = 0; //devpriv->hwdmasize[0];
932 pole = (short *) devpriv->dmabuf[0];
933 devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
934 pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
936 devpriv->rtc_freq = rtc_setfreq_irq(2048);
937 devpriv->rtc_irq_timer.expires =
938 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
939 devpriv->rtc_irq_timer.data = (unsigned long)dev;
940 devpriv->rtc_irq_timer.function = rtc_dropped_irq;
942 add_timer(&devpriv->rtc_irq_timer);
946 devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
947 outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
949 devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
950 outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
956 ==============================================================================
957 ANALOG INPUT MODE 1 or 3, 818 cards
959 static int pcl818_ai_cmd_mode(int mode, struct comedi_device * dev,
960 struct comedi_subdevice * s)
962 struct comedi_cmd *cmd = &s->async->cmd;
963 int divisor1, divisor2;
966 rt_printk("pcl818_ai_cmd_mode()\n");
967 if ((!dev->irq) && (!devpriv->dma_rtc)) {
968 comedi_error(dev, "IRQ not defined!");
972 if (devpriv->irq_blocked)
975 start_pacer(dev, -1, 0, 0); // stop pacer
977 seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
981 setup_channel_list(dev, s, devpriv->ai_chanlist,
982 devpriv->ai_n_chan, seglen);
986 devpriv->ai_act_scan = devpriv->ai_scans;
987 devpriv->ai_act_chan = 0;
988 devpriv->irq_blocked = 1;
989 devpriv->irq_was_now_closed = 0;
990 devpriv->neverending_ai = 0;
991 devpriv->act_chanlist_pos = 0;
992 devpriv->dma_runs_to_end = 0;
994 if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
995 devpriv->neverending_ai = 1; //well, user want neverending
998 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
999 &divisor2, &cmd->convert_arg, TRIG_ROUND_NEAREST);
1000 if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
1004 if (divisor2 == 1) {
1010 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1012 switch (devpriv->dma) {
1015 if (devpriv->dma_rtc == 0) {
1016 pcl818_ai_mode13dma_int(mode, dev, s);
1020 pcl818_ai_mode13dma_rtc(mode, dev, s);
1029 // rt_printk("IRQ\n");
1031 devpriv->ai_mode = INT_TYPE_AI1_INT;
1032 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1034 devpriv->ai_mode = INT_TYPE_AI3_INT;
1035 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1039 outb(1, dev->iobase + PCL818_FI_ENABLE); // enable FIFO
1041 devpriv->ai_mode = INT_TYPE_AI1_FIFO;
1042 outb(0x03, dev->iobase + PCL818_CONTROL); /* Pacer */
1044 devpriv->ai_mode = INT_TYPE_AI3_FIFO;
1045 outb(0x02, dev->iobase + PCL818_CONTROL);
1050 start_pacer(dev, mode, divisor1, divisor2);
1053 switch (devpriv->ai_mode) {
1054 case INT_TYPE_AI1_DMA_RTC:
1055 case INT_TYPE_AI3_DMA_RTC:
1056 set_rtc_irq_bit(1); /* start RTC */
1060 rt_printk("pcl818_ai_cmd_mode() end\n");
1066 ==============================================================================
1067 ANALOG OUTPUT MODE 1 or 3, 818 cards
1069 #ifdef PCL818_MODE13_AO
1070 static int pcl818_ao_mode13(int mode, struct comedi_device * dev, struct comedi_subdevice * s,
1073 int divisor1, divisor2;
1076 comedi_error(dev, "IRQ not defined!");
1080 if (devpriv->irq_blocked)
1083 start_pacer(dev, -1, 0, 0); // stop pacer
1085 devpriv->int13_act_scan = it->n;
1086 devpriv->int13_act_chan = 0;
1087 devpriv->irq_blocked = 1;
1088 devpriv->irq_was_now_closed = 0;
1089 devpriv->neverending_ai = 0;
1090 devpriv->act_chanlist_pos = 0;
1093 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1094 &divisor2, &it->trigvar, TRIG_ROUND_NEAREST);
1095 if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
1099 if (divisor2 == 1) {
1105 outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
1107 devpriv->int818_mode = INT_TYPE_AO1_INT;
1108 outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
1110 devpriv->int818_mode = INT_TYPE_AO3_INT;
1111 outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
1114 start_pacer(dev, mode, divisor1, divisor2);
1120 ==============================================================================
1121 ANALOG OUTPUT MODE 1, 818 cards
1123 static int pcl818_ao_mode1(struct comedi_device * dev, struct comedi_subdevice * s,
1126 return pcl818_ao_mode13(1, dev, s, it);
1130 ==============================================================================
1131 ANALOG OUTPUT MODE 3, 818 cards
1133 static int pcl818_ao_mode3(struct comedi_device * dev, struct comedi_subdevice * s,
1136 return pcl818_ao_mode13(3, dev, s, it);
1142 ==============================================================================
1143 Start/stop pacer onboard pacer
1145 static void start_pacer(struct comedi_device * dev, int mode, unsigned int divisor1,
1146 unsigned int divisor2)
1148 outb(0xb4, dev->iobase + PCL818_CTRCTL);
1149 outb(0x74, dev->iobase + PCL818_CTRCTL);
1153 outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
1154 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
1155 outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
1156 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
1161 ==============================================================================
1162 Check if channel list from user is builded correctly
1163 If it's ok, then program scan/gain logic
1165 static int check_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
1166 unsigned int *chanlist, unsigned int n_chan)
1168 unsigned int chansegment[16];
1169 unsigned int i, nowmustbechan, seglen, segpos;
1171 /* correct channel and range number check itself comedi/range.c */
1173 comedi_error(dev, "range/channel list is empty!");
1178 // first channel is everytime ok
1179 chansegment[0] = chanlist[0];
1180 // build part of chanlist
1181 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
1182 // rt_printk("%d. %d %d\n",i,CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));
1183 // we detect loop, this must by finish
1184 if (chanlist[0] == chanlist[i])
1187 (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
1188 if (nowmustbechan != CR_CHAN(chanlist[i])) { // channel list isn't continous :-(
1190 ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n",
1191 dev->minor, i, CR_CHAN(chanlist[i]),
1192 nowmustbechan, CR_CHAN(chanlist[0]));
1195 // well, this is next correct channel in list
1196 chansegment[i] = chanlist[i];
1199 // check whole chanlist
1200 for (i = 0, segpos = 0; i < n_chan; i++) {
1201 //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]));
1202 if (chanlist[i] != chansegment[i % seglen]) {
1204 ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
1205 dev->minor, i, CR_CHAN(chansegment[i]),
1206 CR_RANGE(chansegment[i]),
1207 CR_AREF(chansegment[i]),
1208 CR_CHAN(chanlist[i % seglen]),
1209 CR_RANGE(chanlist[i % seglen]),
1210 CR_AREF(chansegment[i % seglen]));
1211 return 0; // chan/gain list is strange
1217 rt_printk("check_channel_list: seglen %d\n", seglen);
1221 static void setup_channel_list(struct comedi_device * dev, struct comedi_subdevice * s,
1222 unsigned int *chanlist, unsigned int n_chan, unsigned int seglen)
1226 devpriv->act_chanlist_len = seglen;
1227 devpriv->act_chanlist_pos = 0;
1229 for (i = 0; i < seglen; i++) { // store range list to card
1230 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
1231 outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
1232 outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
1237 /* select channel interval to scan */
1238 outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
1239 1] << 4), dev->iobase + PCL818_MUX);
1243 ==============================================================================
1244 Check if board is switched to SE (1) or DIFF(0) mode
1246 static int check_single_ended(unsigned int port)
1248 if (inb(port + PCL818_STATUS) & 0x20) {
1256 ==============================================================================
1258 static int ai_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
1259 struct comedi_cmd * cmd)
1262 int tmp, divisor1, divisor2;
1264 /* step 1: make sure trigger sources are trivially valid */
1266 tmp = cmd->start_src;
1267 cmd->start_src &= TRIG_NOW;
1268 if (!cmd->start_src || tmp != cmd->start_src)
1271 tmp = cmd->scan_begin_src;
1272 cmd->scan_begin_src &= TRIG_FOLLOW;
1273 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1276 tmp = cmd->convert_src;
1277 cmd->convert_src &= TRIG_TIMER | TRIG_EXT;
1278 if (!cmd->convert_src || tmp != cmd->convert_src)
1281 tmp = cmd->scan_end_src;
1282 cmd->scan_end_src &= TRIG_COUNT;
1283 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1286 tmp = cmd->stop_src;
1287 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
1288 if (!cmd->stop_src || tmp != cmd->stop_src)
1295 /* step 2: make sure trigger sources are unique and mutually compatible */
1297 if (cmd->start_src != TRIG_NOW) {
1298 cmd->start_src = TRIG_NOW;
1301 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1302 cmd->scan_begin_src = TRIG_FOLLOW;
1305 if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT)
1308 if (cmd->scan_end_src != TRIG_COUNT) {
1309 cmd->scan_end_src = TRIG_COUNT;
1313 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
1320 /* step 3: make sure arguments are trivially compatible */
1322 if (cmd->start_arg != 0) {
1327 if (cmd->scan_begin_arg != 0) {
1328 cmd->scan_begin_arg = 0;
1332 if (cmd->convert_src == TRIG_TIMER) {
1333 if (cmd->convert_arg < this_board->ns_min) {
1334 cmd->convert_arg = this_board->ns_min;
1337 } else { /* TRIG_EXT */
1338 if (cmd->convert_arg != 0) {
1339 cmd->convert_arg = 0;
1344 if (!cmd->chanlist_len) {
1345 cmd->chanlist_len = 1;
1348 if (cmd->chanlist_len > s->n_chan) {
1349 cmd->chanlist_len = s->n_chan;
1352 if (cmd->scan_end_arg != cmd->chanlist_len) {
1353 cmd->scan_end_arg = cmd->chanlist_len;
1356 if (cmd->stop_src == TRIG_COUNT) {
1357 if (!cmd->stop_arg) {
1361 } else { /* TRIG_NONE */
1362 if (cmd->stop_arg != 0) {
1372 /* step 4: fix up any arguments */
1374 if (cmd->convert_src == TRIG_TIMER) {
1375 tmp = cmd->convert_arg;
1376 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
1377 &divisor2, &cmd->convert_arg,
1378 cmd->flags & TRIG_ROUND_MASK);
1379 if (cmd->convert_arg < this_board->ns_min)
1380 cmd->convert_arg = this_board->ns_min;
1381 if (tmp != cmd->convert_arg)
1389 /* step 5: complain about special chanlist considerations */
1391 if (cmd->chanlist) {
1392 if (!check_channel_list(dev, s, cmd->chanlist,
1394 return 5; // incorrect channels list
1401 ==============================================================================
1403 static int ai_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
1405 struct comedi_cmd *cmd = &s->async->cmd;
1408 rt_printk("pcl818_ai_cmd()\n");
1409 devpriv->ai_n_chan = cmd->chanlist_len;
1410 devpriv->ai_chanlist = cmd->chanlist;
1411 devpriv->ai_flags = cmd->flags;
1412 devpriv->ai_data_len = s->async->prealloc_bufsz;
1413 devpriv->ai_data = s->async->prealloc_buf;
1414 devpriv->ai_timer1 = 0;
1415 devpriv->ai_timer2 = 0;
1417 if (cmd->stop_src == TRIG_COUNT) {
1418 devpriv->ai_scans = cmd->stop_arg;
1420 devpriv->ai_scans = 0;
1423 if (cmd->scan_begin_src == TRIG_FOLLOW) { // mode 1, 3
1424 if (cmd->convert_src == TRIG_TIMER) { // mode 1
1425 devpriv->ai_timer1 = cmd->convert_arg;
1426 retval = pcl818_ai_cmd_mode(1, dev, s);
1427 rt_printk("pcl818_ai_cmd() end\n");
1430 if (cmd->convert_src == TRIG_EXT) { // mode 3
1431 return pcl818_ai_cmd_mode(3, dev, s);
1439 ==============================================================================
1440 cancel any mode 1-4 AI
1442 static int pcl818_ai_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
1444 if (devpriv->irq_blocked > 0) {
1445 rt_printk("pcl818_ai_cancel()\n");
1446 devpriv->irq_was_now_closed = devpriv->ai_mode;
1447 devpriv->ai_mode = 0;
1449 switch (devpriv->irq_was_now_closed) {
1451 case INT_TYPE_AI1_DMA_RTC:
1452 case INT_TYPE_AI3_DMA_RTC:
1453 set_rtc_irq_bit(0); // stop RTC
1454 del_timer(&devpriv->rtc_irq_timer);
1456 case INT_TYPE_AI1_DMA:
1457 case INT_TYPE_AI3_DMA:
1458 if (devpriv->neverending_ai) {
1459 /* wait for running dma transfer to end, do cleanup in interrupt */
1462 disable_dma(devpriv->dma);
1463 case INT_TYPE_AI1_INT:
1464 case INT_TYPE_AI3_INT:
1465 case INT_TYPE_AI1_FIFO:
1466 case INT_TYPE_AI3_FIFO:
1467 #ifdef PCL818_MODE13_AO
1468 case INT_TYPE_AO1_INT:
1469 case INT_TYPE_AO3_INT:
1471 outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1473 start_pacer(dev, -1, 0, 0);
1474 outb(0, dev->iobase + PCL818_AD_LO);
1475 inb(dev->iobase + PCL818_AD_LO);
1476 inb(dev->iobase + PCL818_AD_HI);
1477 outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
1478 outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
1479 if (devpriv->usefifo) { // FIFO shutdown
1480 outb(0, dev->iobase + PCL818_FI_INTCLR);
1481 outb(0, dev->iobase + PCL818_FI_FLUSH);
1482 outb(0, dev->iobase + PCL818_FI_ENABLE);
1484 devpriv->irq_blocked = 0;
1485 devpriv->last_int_sub = s;
1486 devpriv->neverending_ai = 0;
1492 rt_printk("pcl818_ai_cancel() end\n");
1497 ==============================================================================
1500 static int pcl818_check(unsigned long iobase)
1502 outb(0x00, iobase + PCL818_MUX);
1504 if (inb(iobase + PCL818_MUX) != 0x00)
1505 return 1; //there isn't card
1506 outb(0x55, iobase + PCL818_MUX);
1508 if (inb(iobase + PCL818_MUX) != 0x55)
1509 return 1; //there isn't card
1510 outb(0x00, iobase + PCL818_MUX);
1512 outb(0x18, iobase + PCL818_CONTROL);
1514 if (inb(iobase + PCL818_CONTROL) != 0x18)
1515 return 1; //there isn't card
1516 return 0; // ok, card exist
1520 ==============================================================================
1521 reset whole PCL-818 cards
1523 static void pcl818_reset(struct comedi_device * dev)
1525 if (devpriv->usefifo) { // FIFO shutdown
1526 outb(0, dev->iobase + PCL818_FI_INTCLR);
1527 outb(0, dev->iobase + PCL818_FI_FLUSH);
1528 outb(0, dev->iobase + PCL818_FI_ENABLE);
1530 outb(0, dev->iobase + PCL818_DA_LO); // DAC=0V
1531 outb(0, dev->iobase + PCL818_DA_HI);
1533 outb(0, dev->iobase + PCL818_DO_HI); // DO=$0000
1534 outb(0, dev->iobase + PCL818_DO_LO);
1536 outb(0, dev->iobase + PCL818_CONTROL);
1537 outb(0, dev->iobase + PCL818_CNTENABLE);
1538 outb(0, dev->iobase + PCL818_MUX);
1539 outb(0, dev->iobase + PCL818_CLRINT);
1540 outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
1541 outb(0x70, dev->iobase + PCL818_CTRCTL);
1542 outb(0x30, dev->iobase + PCL818_CTRCTL);
1543 if (this_board->is_818) {
1544 outb(0, dev->iobase + PCL818_RANGE);
1546 outb(0, dev->iobase + PCL718_DA2_LO);
1547 outb(0, dev->iobase + PCL718_DA2_HI);
1553 ==============================================================================
1554 Enable(1)/disable(0) periodic interrupts from RTC
1556 static int set_rtc_irq_bit(unsigned char bit)
1559 unsigned long flags;
1563 if (RTC_timer_lock > 1)
1567 if (RTC_timer_lock < 0)
1569 if (RTC_timer_lock > 0)
1575 val = CMOS_READ(RTC_CONTROL);
1581 CMOS_WRITE(val, RTC_CONTROL);
1582 CMOS_READ(RTC_INTR_FLAGS);
1583 restore_flags(flags);
1588 ==============================================================================
1589 Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
1591 static void rtc_dropped_irq(unsigned long data)
1593 struct comedi_device *dev = (void *)data;
1594 unsigned long flags, tmp;
1596 switch (devpriv->int818_mode) {
1597 case INT_TYPE_AI1_DMA_RTC:
1598 case INT_TYPE_AI3_DMA_RTC:
1599 mod_timer(&devpriv->rtc_irq_timer,
1600 jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
1603 tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
1604 restore_flags(flags);
1610 ==============================================================================
1611 Set frequency of interrupts from RTC
1613 static int rtc_setfreq_irq(int freq)
1618 unsigned long flags;
1625 while (freq > (1 << tmp))
1628 rtc_freq = 1 << tmp;
1632 val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
1634 CMOS_WRITE(val, RTC_FREQ_SELECT);
1635 restore_flags(flags);
1641 ==============================================================================
1642 Free any resources that we have claimed
1644 static void free_resources(struct comedi_device * dev)
1646 //rt_printk("free_resource()\n");
1648 pcl818_ai_cancel(dev, devpriv->sub_ai);
1651 free_dma(devpriv->dma);
1652 if (devpriv->dmabuf[0])
1653 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1654 if (devpriv->dmabuf[1])
1655 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1657 if (devpriv->rtc_irq)
1658 comedi_free_irq(devpriv->rtc_irq, dev);
1659 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1660 if (devpriv->rtc_iobase)
1661 release_region(devpriv->rtc_iobase,
1662 devpriv->rtc_iosize);
1664 if (devpriv->dma_rtc)
1670 free_irq(dev->irq, dev);
1672 release_region(dev->iobase, devpriv->io_range);
1673 //rt_printk("free_resource() end\n");
1677 ==============================================================================
1682 static int pcl818_attach(struct comedi_device * dev, struct comedi_devconfig * it)
1685 unsigned long iobase;
1686 unsigned int irq, dma;
1687 unsigned long pages;
1688 struct comedi_subdevice *s;
1690 if ((ret = alloc_private(dev, sizeof(struct pcl818_private))) < 0)
1691 return ret; /* Can't alloc mem */
1693 /* claim our I/O space */
1694 iobase = it->options[0];
1695 printk("comedi%d: pcl818: board=%s, ioport=0x%03lx",
1696 dev->minor, this_board->name, iobase);
1697 devpriv->io_range = this_board->io_range;
1698 if ((this_board->fifo) && (it->options[2] == -1)) { // we've board with FIFO and we want to use FIFO
1699 devpriv->io_range = PCLx1xFIFO_RANGE;
1700 devpriv->usefifo = 1;
1702 if (!request_region(iobase, devpriv->io_range, "pcl818")) {
1703 rt_printk("I/O port conflict\n");
1707 dev->iobase = iobase;
1709 if (pcl818_check(iobase)) {
1710 rt_printk(", I can't detect board. FAIL!\n");
1714 /* set up some name stuff */
1715 dev->board_name = this_board->name;
1718 if (this_board->IRQbits != 0) { /* board support IRQ */
1719 irq = it->options[1];
1720 if (irq) { /* we want to use IRQ */
1721 if (((1 << irq) & this_board->IRQbits) == 0) {
1723 (", IRQ %u is out of allowed range, DISABLING IT",
1725 irq = 0; /* Bad IRQ */
1727 if (comedi_request_irq(irq, interrupt_pcl818, 0,
1730 (", unable to allocate IRQ %u, DISABLING IT",
1732 irq = 0; /* Can't use IRQ */
1734 rt_printk(", irq=%u", irq);
1742 devpriv->irq_free = 1;
1743 } /* 1=we have allocated irq */
1745 devpriv->irq_free = 0;
1747 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1748 devpriv->ai_mode = 0; /* mode of irq */
1751 /* grab RTC for DMA operations */
1752 devpriv->dma_rtc = 0;
1753 if (it->options[2] > 0) { // we want to use DMA
1754 if (RTC_lock == 0) {
1755 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1759 devpriv->rtc_iobase = RTC_PORT(0);
1760 devpriv->rtc_iosize = RTC_IO_EXTENT;
1762 if (!comedi_request_irq(RTC_IRQ,
1763 interrupt_pcl818_ai_mode13_dma_rtc, 0,
1764 "pcl818 DMA (RTC)", dev)) {
1765 devpriv->dma_rtc = 1;
1766 devpriv->rtc_irq = RTC_IRQ;
1767 rt_printk(", dma_irq=%u", devpriv->rtc_irq);
1770 if (RTC_lock == 0) {
1771 if (devpriv->rtc_iobase)
1772 release_region(devpriv->rtc_iobase,
1773 devpriv->rtc_iosize);
1775 devpriv->rtc_iobase = 0;
1776 devpriv->rtc_iosize = 0;
1785 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1786 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1787 if (this_board->DMAbits != 0) { /* board support DMA */
1788 dma = it->options[2];
1790 goto no_dma; /* DMA disabled */
1791 if (((1 << dma) & this_board->DMAbits) == 0) {
1792 rt_printk(", DMA is out of allowed range, FAIL!\n");
1793 return -EINVAL; /* Bad DMA */
1795 ret = request_dma(dma, "pcl818");
1797 rt_printk(", unable to allocate DMA %u, FAIL!\n", dma);
1798 return -EBUSY; /* DMA isn't free */
1801 rt_printk(", dma=%u", dma);
1802 pages = 2; /* we need 16KB */
1803 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1804 if (!devpriv->dmabuf[0]) {
1805 rt_printk(", unable to allocate DMA buffer, FAIL!\n");
1806 /* maybe experiment with try_to_free_pages() will help .... */
1807 return -EBUSY; /* no buffer :-( */
1809 devpriv->dmapages[0] = pages;
1810 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1811 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1812 //rt_printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE);
1813 if (devpriv->dma_rtc == 0) { // we must do duble buff :-(
1814 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1815 if (!devpriv->dmabuf[1]) {
1817 (", unable to allocate DMA buffer, FAIL!\n");
1820 devpriv->dmapages[1] = pages;
1821 devpriv->hwdmaptr[1] =
1822 virt_to_bus((void *)devpriv->dmabuf[1]);
1823 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1829 if ((ret = alloc_subdevices(dev, 4)) < 0)
1832 s = dev->subdevices + 0;
1833 if (!this_board->n_aichan_se) {
1834 s->type = COMEDI_SUBD_UNUSED;
1836 s->type = COMEDI_SUBD_AI;
1837 devpriv->sub_ai = s;
1838 s->subdev_flags = SDF_READABLE;
1839 if (check_single_ended(dev->iobase)) {
1840 s->n_chan = this_board->n_aichan_se;
1841 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1842 printk(", %dchans S.E. DAC", s->n_chan);
1844 s->n_chan = this_board->n_aichan_diff;
1845 s->subdev_flags |= SDF_DIFF;
1846 printk(", %dchans DIFF DAC", s->n_chan);
1848 s->maxdata = this_board->ai_maxdata;
1849 s->len_chanlist = s->n_chan;
1850 s->range_table = this_board->ai_range_type;
1851 s->cancel = pcl818_ai_cancel;
1852 s->insn_read = pcl818_ai_insn_read;
1853 if ((irq) || (devpriv->dma_rtc)) {
1854 dev->read_subdev = s;
1855 s->subdev_flags |= SDF_CMD_READ;
1856 s->do_cmdtest = ai_cmdtest;
1859 if (this_board->is_818) {
1860 if ((it->options[4] == 1) || (it->options[4] == 10))
1861 s->range_table = &range_pcl818l_h_ai; // secondary range list jumper selectable
1863 switch (it->options[4]) {
1865 s->range_table = &range_bipolar10;
1868 s->range_table = &range_bipolar5;
1871 s->range_table = &range_bipolar2_5;
1874 s->range_table = &range718_bipolar1;
1877 s->range_table = &range718_bipolar0_5;
1880 s->range_table = &range_unipolar10;
1883 s->range_table = &range_unipolar5;
1886 s->range_table = &range718_unipolar2;
1889 s->range_table = &range718_unipolar1;
1892 s->range_table = &range_unknown;
1898 s = dev->subdevices + 1;
1899 if (!this_board->n_aochan) {
1900 s->type = COMEDI_SUBD_UNUSED;
1902 s->type = COMEDI_SUBD_AO;
1903 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1904 s->n_chan = this_board->n_aochan;
1905 s->maxdata = this_board->ao_maxdata;
1906 s->len_chanlist = this_board->n_aochan;
1907 s->range_table = this_board->ao_range_type;
1908 s->insn_read = pcl818_ao_insn_read;
1909 s->insn_write = pcl818_ao_insn_write;
1911 #ifdef PCL818_MODE13_AO
1913 s->trig[1] = pcl818_ao_mode1;
1914 s->trig[3] = pcl818_ao_mode3;
1918 if (this_board->is_818) {
1919 if ((it->options[4] == 1) || (it->options[4] == 10))
1920 s->range_table = &range_unipolar10;
1921 if (it->options[4] == 2)
1922 s->range_table = &range_unknown;
1924 if ((it->options[5] == 1) || (it->options[5] == 10))
1925 s->range_table = &range_unipolar10;
1926 if (it->options[5] == 2)
1927 s->range_table = &range_unknown;
1931 s = dev->subdevices + 2;
1932 if (!this_board->n_dichan) {
1933 s->type = COMEDI_SUBD_UNUSED;
1935 s->type = COMEDI_SUBD_DI;
1936 s->subdev_flags = SDF_READABLE;
1937 s->n_chan = this_board->n_dichan;
1939 s->len_chanlist = this_board->n_dichan;
1940 s->range_table = &range_digital;
1941 s->insn_bits = pcl818_di_insn_bits;
1944 s = dev->subdevices + 3;
1945 if (!this_board->n_dochan) {
1946 s->type = COMEDI_SUBD_UNUSED;
1948 s->type = COMEDI_SUBD_DO;
1949 s->subdev_flags = SDF_WRITABLE;
1950 s->n_chan = this_board->n_dochan;
1952 s->len_chanlist = this_board->n_dochan;
1953 s->range_table = &range_digital;
1954 s->insn_bits = pcl818_do_insn_bits;
1957 /* select 1/10MHz oscilator */
1958 if ((it->options[3] == 0) || (it->options[3] == 10)) {
1959 devpriv->i8253_osc_base = 100;
1961 devpriv->i8253_osc_base = 1000;
1964 /* max sampling speed */
1965 devpriv->ns_min = this_board->ns_min;
1967 if (!this_board->is_818) {
1968 if ((it->options[6] == 1) || (it->options[6] == 100))
1969 devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
1980 ==============================================================================
1983 static int pcl818_detach(struct comedi_device * dev)
1985 // rt_printk("comedi%d: pcl818: remove\n", dev->minor);
1986 free_resources(dev);