2 comedi/drivers/pcl816.c
4 Author: Juan Grigera <juan@grigera.com.ar>
5 based on pcl818 by Michal Dobes <dobes@tesnet.cz> and bits of pcl812
7 hardware driver for Advantech cards:
13 Description: Advantech PCL-816 cards, PCL-814
14 Author: Juan Grigera <juan@grigera.com.ar>
15 Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b)
17 Updated: Tue, 2 Apr 2002 23:15:21 -0800
19 PCL 816 and 814B have 16 SE/DIFF ADCs, 16 DACs, 16 DI and 16 DO.
20 Differences are at resolution (16 vs 12 bits).
22 The driver support AI command mode, other subdevices not written.
24 Analog output and digital input and output are not supported.
26 Configuration Options:
28 [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
29 [2] - DMA (0=disable, 1, 3)
30 [3] - 0, 10=10MHz clock for 8254
31 1= 1MHz clock for 8254
35 #include "../comedidev.h"
37 #include <linux/ioport.h>
38 #include <linux/mc146818rtc.h>
39 #include <linux/gfp.h>
40 #include <linux/delay.h>
48 /* boards constants */
50 #define PCLx1x_RANGE 16
52 /* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
54 /* INTEL 8254 counters */
58 /* R: counter read-back register W: counter control */
59 #define PCL816_CTRCTL 7
61 /* R: A/D high byte W: A/D range control */
62 #define PCL816_RANGE 9
63 /* W: clear INT request */
64 #define PCL816_CLRINT 10
65 /* R: next mux scan channel W: mux scan channel & range control pointer */
67 /* R/W: operation control register */
68 #define PCL816_CONTROL 12
70 /* R: return status byte W: set DMA/IRQ */
71 #define PCL816_STATUS 13
72 #define PCL816_STATUS_DRDY_MASK 0x80
74 /* R: low byte of A/D W: soft A/D trigger */
75 #define PCL816_AD_LO 8
76 /* R: high byte of A/D W: A/D range control */
77 #define PCL816_AD_HI 9
79 /* type of interrupt handler */
80 #define INT_TYPE_AI1_INT 1
81 #define INT_TYPE_AI1_DMA 2
82 #define INT_TYPE_AI3_INT 4
83 #define INT_TYPE_AI3_DMA 5
85 #define INT_TYPE_AI1_DMA_RTC 9
86 #define INT_TYPE_AI3_DMA_RTC 10
90 #define RTC_IO_EXTENT 0x10
93 #define MAGIC_DMA_WORD 0x5a5a
95 static const struct comedi_lrange range_pcl816 = { 8, {
107 struct pcl816_board {
109 const char *name; /* board name */
110 int n_ranges; /* len of range list */
111 int n_aichan; /* num of A/D chans in diferencial mode */
112 unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */
113 int n_aochan; /* num of D/A chans */
114 int n_dichan; /* num of DI chans */
115 int n_dochan; /* num of DO chans */
116 const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
117 const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
118 unsigned int io_range; /* len of IO space */
119 unsigned int IRQbits; /* allowed interrupts */
120 unsigned int DMAbits; /* allowed DMA chans */
121 int ai_maxdata; /* maxdata for A/D */
122 int ao_maxdata; /* maxdata for D/A */
123 int ai_chanlist; /* allowed len of channel list A/D */
124 int ao_chanlist; /* allowed len of channel list D/A */
125 int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
128 #define devpriv ((struct pcl816_private *)dev->private)
131 static int RTC_lock; /* RTC lock */
132 static int RTC_timer_lock; /* RTC int lock */
135 struct pcl816_private {
137 unsigned int dma; /* used DMA, 0=don't use DMA */
138 int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
140 unsigned long rtc_iobase; /* RTC port region */
141 unsigned int rtc_iosize;
142 unsigned int rtc_irq;
144 unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
145 unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
146 unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
147 unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
148 unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
149 unsigned int last_top_dma; /* DMA pointer in last RTC int */
150 int next_dma_buf; /* which DMA buffer will be used next round */
151 long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
152 unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
154 unsigned int ai_scans; /* len of scanlist */
155 unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */
156 int irq_free; /* 1=have allocated IRQ */
157 int irq_blocked; /* 1=IRQ now uses any subdev */
159 int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
161 int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */
162 int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
163 struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
164 int ai_act_scan; /* how many scans we finished */
165 unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */
166 unsigned int ai_act_chanlist_len; /* how long is actual MUX list */
167 unsigned int ai_act_chanlist_pos; /* actual position in MUX list */
168 unsigned int ai_n_chan; /* how many channels per scan */
169 unsigned int ai_poll_ptr; /* how many sampes transfer poll */
170 struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
172 struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
173 unsigned long rtc_freq; /* RTC int freq */
178 ==============================================================================
180 static int check_channel_list(struct comedi_device *dev,
181 struct comedi_subdevice *s,
182 unsigned int *chanlist, unsigned int chanlen);
183 static void setup_channel_list(struct comedi_device *dev,
184 struct comedi_subdevice *s,
185 unsigned int *chanlist, unsigned int seglen);
186 static int pcl816_ai_cancel(struct comedi_device *dev,
187 struct comedi_subdevice *s);
188 static void start_pacer(struct comedi_device *dev, int mode,
189 unsigned int divisor1, unsigned int divisor2);
191 static int set_rtc_irq_bit(unsigned char bit);
194 static int pcl816_ai_cmdtest(struct comedi_device *dev,
195 struct comedi_subdevice *s,
196 struct comedi_cmd *cmd);
197 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
200 ==============================================================================
201 ANALOG INPUT MODE0, 816 cards, slow version
203 static int pcl816_ai_insn_read(struct comedi_device *dev,
204 struct comedi_subdevice *s,
205 struct comedi_insn *insn, unsigned int *data)
210 DPRINTK("mode 0 analog input\n");
211 /* software trigger, DMA and INT off */
212 outb(0, dev->iobase + PCL816_CONTROL);
213 /* clear INT (conversion end) flag */
214 outb(0, dev->iobase + PCL816_CLRINT);
216 /* Set the input channel */
217 outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
219 outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
221 for (n = 0; n < insn->n; n++) {
223 outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */
227 if (!(inb(dev->iobase + PCL816_STATUS) &
228 PCL816_STATUS_DRDY_MASK)) {
229 /* return read value */
232 PCL816_AD_HI) << 8) |
233 (inb(dev->iobase + PCL816_AD_LO)));
234 /* clear INT (conversion end) flag */
235 outb(0, dev->iobase + PCL816_CLRINT);
240 /* Return timeout error */
242 comedi_error(dev, "A/D insn timeout\n");
244 /* clear INT (conversion end) flag */
245 outb(0, dev->iobase + PCL816_CLRINT);
254 ==============================================================================
255 analog input interrupt mode 1 & 3, 818 cards
256 one sample per interrupt version
258 static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
260 struct comedi_device *dev = d;
261 struct comedi_subdevice *s = dev->subdevices + 0;
263 int timeout = 50; /* wait max 50us */
266 if (!(inb(dev->iobase + PCL816_STATUS) &
267 PCL816_STATUS_DRDY_MASK))
271 if (!timeout) { /* timeout, bail error */
272 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
273 comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
274 pcl816_ai_cancel(dev, s);
275 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
276 comedi_event(dev, s);
282 low = inb(dev->iobase + PCL816_AD_LO);
283 hi = inb(dev->iobase + PCL816_AD_HI);
285 comedi_buf_put(s->async, (hi << 8) | low);
287 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
289 if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
290 devpriv->ai_act_chanlist_pos = 0;
292 s->async->cur_chan++;
293 if (s->async->cur_chan >= devpriv->ai_n_chan) {
294 s->async->cur_chan = 0;
295 devpriv->ai_act_scan++;
298 if (!devpriv->ai_neverending)
299 /* all data sampled */
300 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
301 /* all data sampled */
302 pcl816_ai_cancel(dev, s);
303 s->async->events |= COMEDI_CB_EOA;
305 comedi_event(dev, s);
310 ==============================================================================
311 analog input dma mode 1 & 3, 816 cards
313 static void transfer_from_dma_buf(struct comedi_device *dev,
314 struct comedi_subdevice *s, short *ptr,
315 unsigned int bufptr, unsigned int len)
319 s->async->events = 0;
321 for (i = 0; i < len; i++) {
323 comedi_buf_put(s->async, ptr[bufptr++]);
325 if (++devpriv->ai_act_chanlist_pos >=
326 devpriv->ai_act_chanlist_len) {
327 devpriv->ai_act_chanlist_pos = 0;
330 s->async->cur_chan++;
331 if (s->async->cur_chan >= devpriv->ai_n_chan) {
332 s->async->cur_chan = 0;
333 devpriv->ai_act_scan++;
336 if (!devpriv->ai_neverending)
337 /* all data sampled */
338 if (devpriv->ai_act_scan >= devpriv->ai_scans) {
339 pcl816_ai_cancel(dev, s);
340 s->async->events |= COMEDI_CB_EOA;
341 s->async->events |= COMEDI_CB_BLOCK;
346 comedi_event(dev, s);
349 static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
351 struct comedi_device *dev = d;
352 struct comedi_subdevice *s = dev->subdevices + 0;
353 int len, bufptr, this_dma_buf;
354 unsigned long dma_flags;
357 disable_dma(devpriv->dma);
358 this_dma_buf = devpriv->next_dma_buf;
360 /* switch dma bufs */
361 if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
363 devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
364 set_dma_mode(devpriv->dma, DMA_MODE_READ);
365 dma_flags = claim_dma_lock();
366 /* clear_dma_ff (devpriv->dma); */
367 set_dma_addr(devpriv->dma,
368 devpriv->hwdmaptr[devpriv->next_dma_buf]);
369 if (devpriv->dma_runs_to_end) {
370 set_dma_count(devpriv->dma,
371 devpriv->hwdmasize[devpriv->
374 set_dma_count(devpriv->dma, devpriv->last_dma_run);
376 release_dma_lock(dma_flags);
377 enable_dma(devpriv->dma);
380 devpriv->dma_runs_to_end--;
381 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
383 ptr = (short *)devpriv->dmabuf[this_dma_buf];
385 len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
386 bufptr = devpriv->ai_poll_ptr;
387 devpriv->ai_poll_ptr = 0;
389 transfer_from_dma_buf(dev, s, ptr, bufptr, len);
394 ==============================================================================
397 static irqreturn_t interrupt_pcl816(int irq, void *d)
399 struct comedi_device *dev = d;
402 if (!dev->attached) {
403 comedi_error(dev, "premature interrupt");
407 switch (devpriv->int816_mode) {
408 case INT_TYPE_AI1_DMA:
409 case INT_TYPE_AI3_DMA:
410 return interrupt_pcl816_ai_mode13_dma(irq, d);
411 case INT_TYPE_AI1_INT:
412 case INT_TYPE_AI3_INT:
413 return interrupt_pcl816_ai_mode13_int(irq, d);
416 outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
417 if (!dev->irq || !devpriv->irq_free || !devpriv->irq_blocked ||
418 !devpriv->int816_mode) {
419 if (devpriv->irq_was_now_closed) {
420 devpriv->irq_was_now_closed = 0;
421 /* comedi_error(dev,"last IRQ.."); */
424 comedi_error(dev, "bad IRQ!");
427 comedi_error(dev, "IRQ from unknown source!");
432 ==============================================================================
435 static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
437 printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
438 cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
439 printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
440 cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
441 printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
442 cmd->stop_src, cmd->scan_end_src);
443 printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
444 e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
448 ==============================================================================
450 static int pcl816_ai_cmdtest(struct comedi_device *dev,
451 struct comedi_subdevice *s, struct comedi_cmd *cmd)
453 const struct pcl816_board *board = comedi_board(dev);
455 int tmp, divisor1 = 0, divisor2 = 0;
457 DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
458 pcl816_cmdtest_out(-1, cmd);
461 /* step 1: make sure trigger sources are trivially valid */
462 tmp = cmd->start_src;
463 cmd->start_src &= TRIG_NOW;
464 if (!cmd->start_src || tmp != cmd->start_src)
467 tmp = cmd->scan_begin_src;
468 cmd->scan_begin_src &= TRIG_FOLLOW;
469 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
472 tmp = cmd->convert_src;
473 cmd->convert_src &= TRIG_EXT | TRIG_TIMER;
474 if (!cmd->convert_src || tmp != cmd->convert_src)
477 tmp = cmd->scan_end_src;
478 cmd->scan_end_src &= TRIG_COUNT;
479 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
483 cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
484 if (!cmd->stop_src || tmp != cmd->stop_src)
492 * step 2: make sure trigger sources
493 * are unique and mutually compatible
496 if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) {
497 cmd->convert_src = TRIG_TIMER;
501 if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
508 /* step 3: make sure arguments are trivially compatible */
509 if (cmd->start_arg != 0) {
514 if (cmd->scan_begin_arg != 0) {
515 cmd->scan_begin_arg = 0;
518 if (cmd->convert_src == TRIG_TIMER) {
519 if (cmd->convert_arg < board->ai_ns_min) {
520 cmd->convert_arg = board->ai_ns_min;
523 } else { /* TRIG_EXT */
524 if (cmd->convert_arg != 0) {
525 cmd->convert_arg = 0;
530 if (cmd->scan_end_arg != cmd->chanlist_len) {
531 cmd->scan_end_arg = cmd->chanlist_len;
534 if (cmd->stop_src == TRIG_COUNT) {
535 if (!cmd->stop_arg) {
539 } else { /* TRIG_NONE */
540 if (cmd->stop_arg != 0) {
550 /* step 4: fix up any arguments */
551 if (cmd->convert_src == TRIG_TIMER) {
552 tmp = cmd->convert_arg;
553 i8253_cascade_ns_to_timer(board->i8254_osc_base,
554 &divisor1, &divisor2,
556 cmd->flags & TRIG_ROUND_MASK);
557 if (cmd->convert_arg < board->ai_ns_min)
558 cmd->convert_arg = board->ai_ns_min;
559 if (tmp != cmd->convert_arg)
567 /* step 5: complain about special chanlist considerations */
570 if (!check_channel_list(dev, s, cmd->chanlist,
572 return 5; /* incorrect channels list */
578 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
580 const struct pcl816_board *board = comedi_board(dev);
581 unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
582 struct comedi_cmd *cmd = &s->async->cmd;
585 if (cmd->start_src != TRIG_NOW)
587 if (cmd->scan_begin_src != TRIG_FOLLOW)
589 if (cmd->scan_end_src != TRIG_COUNT)
591 if (cmd->scan_end_arg != cmd->chanlist_len)
593 /* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
594 if (devpriv->irq_blocked)
597 if (cmd->convert_src == TRIG_TIMER) {
598 if (cmd->convert_arg < board->ai_ns_min)
599 cmd->convert_arg = board->ai_ns_min;
601 i8253_cascade_ns_to_timer(board->i8254_osc_base, &divisor1,
602 &divisor2, &cmd->convert_arg,
603 cmd->flags & TRIG_ROUND_MASK);
605 /* PCL816 crash if any divisor is set to 1 */
616 start_pacer(dev, -1, 0, 0); /* stop pacer */
618 seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
621 setup_channel_list(dev, s, cmd->chanlist, seglen);
624 devpriv->ai_n_chan = cmd->chanlist_len;
625 devpriv->ai_act_scan = 0;
626 s->async->cur_chan = 0;
627 devpriv->irq_blocked = 1;
628 devpriv->ai_poll_ptr = 0;
629 devpriv->irq_was_now_closed = 0;
631 if (cmd->stop_src == TRIG_COUNT) {
632 devpriv->ai_scans = cmd->stop_arg;
633 devpriv->ai_neverending = 0;
635 devpriv->ai_scans = 0;
636 devpriv->ai_neverending = 1;
639 /* don't we want wake up every scan? */
640 if ((cmd->flags & TRIG_WAKE_EOS)) {
642 "pl816: You wankt WAKE_EOS but I dont want handle it");
643 /* devpriv->ai_eos=1; */
644 /* if (devpriv->ai_n_chan==1) */
645 /* devpriv->dma=0; // DMA is useless for this situation */
649 bytes = devpriv->hwdmasize[0];
650 if (!devpriv->ai_neverending) {
652 bytes = s->async->cmd.chanlist_len *
653 s->async->cmd.chanlist_len *
656 /* how many DMA pages we must fill */
657 devpriv->dma_runs_to_end = bytes /
658 devpriv->hwdmasize[0];
660 /* on last dma transfer must be moved */
661 devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
662 devpriv->dma_runs_to_end--;
663 if (devpriv->dma_runs_to_end >= 0)
664 bytes = devpriv->hwdmasize[0];
666 devpriv->dma_runs_to_end = -1;
668 devpriv->next_dma_buf = 0;
669 set_dma_mode(devpriv->dma, DMA_MODE_READ);
670 dma_flags = claim_dma_lock();
671 clear_dma_ff(devpriv->dma);
672 set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
673 set_dma_count(devpriv->dma, bytes);
674 release_dma_lock(dma_flags);
675 enable_dma(devpriv->dma);
678 start_pacer(dev, 1, divisor1, divisor2);
679 dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
681 switch (cmd->convert_src) {
683 devpriv->int816_mode = INT_TYPE_AI1_DMA;
686 outb(0x32, dev->iobase + PCL816_CONTROL);
688 /* write irq and DMA to card */
689 outb(dmairq, dev->iobase + PCL816_STATUS);
693 devpriv->int816_mode = INT_TYPE_AI3_DMA;
695 /* Ext trig+IRQ+DMA */
696 outb(0x34, dev->iobase + PCL816_CONTROL);
698 /* write irq to card */
699 outb(dmairq, dev->iobase + PCL816_STATUS);
703 DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
707 static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
710 unsigned int top1, top2, i;
713 return 0; /* poll is valid only for DMA transfer */
715 spin_lock_irqsave(&dev->spinlock, flags);
717 for (i = 0; i < 20; i++) {
718 top1 = get_dma_residue(devpriv->dma); /* where is now DMA */
719 top2 = get_dma_residue(devpriv->dma);
724 spin_unlock_irqrestore(&dev->spinlock, flags);
728 /* where is now DMA in buffer */
729 top1 = devpriv->hwdmasize[0] - top1;
730 top1 >>= 1; /* sample position */
731 top2 = top1 - devpriv->ai_poll_ptr;
732 if (top2 < 1) { /* no new samples */
733 spin_unlock_irqrestore(&dev->spinlock, flags);
737 transfer_from_dma_buf(dev, s,
738 (short *)devpriv->dmabuf[devpriv->next_dma_buf],
739 devpriv->ai_poll_ptr, top2);
741 devpriv->ai_poll_ptr = top1; /* new buffer position */
742 spin_unlock_irqrestore(&dev->spinlock, flags);
744 return s->async->buf_write_count - s->async->buf_read_count;
748 ==============================================================================
749 cancel any mode 1-4 AI
751 static int pcl816_ai_cancel(struct comedi_device *dev,
752 struct comedi_subdevice *s)
754 /* DEBUG(printk("pcl816_ai_cancel()\n");) */
756 if (devpriv->irq_blocked > 0) {
757 switch (devpriv->int816_mode) {
759 case INT_TYPE_AI1_DMA_RTC:
760 case INT_TYPE_AI3_DMA_RTC:
761 set_rtc_irq_bit(0); /* stop RTC */
762 del_timer(&devpriv->rtc_irq_timer);
764 case INT_TYPE_AI1_DMA:
765 case INT_TYPE_AI3_DMA:
766 disable_dma(devpriv->dma);
767 case INT_TYPE_AI1_INT:
768 case INT_TYPE_AI3_INT:
769 outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
770 dev->iobase + PCL816_CONTROL); /* Stop A/D */
772 outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
775 outb(0xb0, dev->iobase + PCL816_CTRCTL);
776 outb(0x70, dev->iobase + PCL816_CTRCTL);
777 outb(0, dev->iobase + PCL816_AD_LO);
778 inb(dev->iobase + PCL816_AD_LO);
779 inb(dev->iobase + PCL816_AD_HI);
781 /* clear INT request */
782 outb(0, dev->iobase + PCL816_CLRINT);
785 outb(0, dev->iobase + PCL816_CONTROL);
786 devpriv->irq_blocked = 0;
787 devpriv->irq_was_now_closed = devpriv->int816_mode;
788 devpriv->int816_mode = 0;
789 devpriv->last_int_sub = s;
795 DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
800 ==============================================================================
803 static int pcl816_check(unsigned long iobase)
805 outb(0x00, iobase + PCL816_MUX);
807 if (inb(iobase + PCL816_MUX) != 0x00)
808 return 1; /* there isn't card */
809 outb(0x55, iobase + PCL816_MUX);
811 if (inb(iobase + PCL816_MUX) != 0x55)
812 return 1; /* there isn't card */
813 outb(0x00, iobase + PCL816_MUX);
815 outb(0x18, iobase + PCL816_CONTROL);
817 if (inb(iobase + PCL816_CONTROL) != 0x18)
818 return 1; /* there isn't card */
819 return 0; /* ok, card exist */
823 ==============================================================================
824 reset whole PCL-816 cards
826 static void pcl816_reset(struct comedi_device *dev)
828 /* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */
829 /* outb (0, dev->iobase + PCL818_DA_HI); */
831 /* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */
832 /* outb (0, dev->iobase + PCL818_DO_LO); */
834 outb(0, dev->iobase + PCL816_CONTROL);
835 outb(0, dev->iobase + PCL816_MUX);
836 outb(0, dev->iobase + PCL816_CLRINT);
837 outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */
838 outb(0x70, dev->iobase + PCL816_CTRCTL);
839 outb(0x30, dev->iobase + PCL816_CTRCTL);
840 outb(0, dev->iobase + PCL816_RANGE);
844 ==============================================================================
845 Start/stop pacer onboard pacer
848 start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
849 unsigned int divisor2)
851 outb(0x32, dev->iobase + PCL816_CTRCTL);
852 outb(0xff, dev->iobase + PCL816_CTR0);
853 outb(0x00, dev->iobase + PCL816_CTR0);
856 /* set counter 2 as mode 3 */
857 outb(0xb4, dev->iobase + PCL816_CTRCTL);
858 /* set counter 1 as mode 3 */
859 outb(0x74, dev->iobase + PCL816_CTRCTL);
863 DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
865 outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
866 outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
867 outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
868 outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
871 /* clear pending interrupts (just in case) */
872 /* outb(0, dev->iobase + PCL816_CLRINT); */
876 ==============================================================================
877 Check if channel list from user is builded correctly
878 If it's ok, then return non-zero length of repeated segment of channel list
881 check_channel_list(struct comedi_device *dev,
882 struct comedi_subdevice *s, unsigned int *chanlist,
883 unsigned int chanlen)
885 unsigned int chansegment[16];
886 unsigned int i, nowmustbechan, seglen, segpos;
888 /* correct channel and range number check itself comedi/range.c */
890 comedi_error(dev, "range/channel list is empty!");
895 /* first channel is every time ok */
896 chansegment[0] = chanlist[0];
897 for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
898 /* build part of chanlist */
899 DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
900 CR_CHAN(chanlist[i]),
901 CR_RANGE(chanlist[i]));)
903 /* we detect loop, this must by finish */
904 if (chanlist[0] == chanlist[i])
907 (CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
908 if (nowmustbechan != CR_CHAN(chanlist[i])) {
909 /* channel list isn't continuous :-( */
911 "comedi%d: pcl816: channel list must "
912 "be continuous! chanlist[%i]=%d but "
913 "must be %d or %d!\n", dev->minor,
914 i, CR_CHAN(chanlist[i]), nowmustbechan,
915 CR_CHAN(chanlist[0]));
918 /* well, this is next correct channel in list */
919 chansegment[i] = chanlist[i];
922 /* check whole chanlist */
923 for (i = 0, segpos = 0; i < chanlen; i++) {
924 DEBUG(printk("%d %d=%d %d\n",
925 CR_CHAN(chansegment[i % seglen]),
926 CR_RANGE(chansegment[i % seglen]),
927 CR_CHAN(chanlist[i]),
928 CR_RANGE(chanlist[i]));)
929 if (chanlist[i] != chansegment[i % seglen]) {
931 "comedi%d: pcl816: bad channel or range"
932 " number! chanlist[%i]=%d,%d,%d and not"
933 " %d,%d,%d!\n", dev->minor, i,
934 CR_CHAN(chansegment[i]),
935 CR_RANGE(chansegment[i]),
936 CR_AREF(chansegment[i]),
937 CR_CHAN(chanlist[i % seglen]),
938 CR_RANGE(chanlist[i % seglen]),
939 CR_AREF(chansegment[i % seglen]));
940 return 0; /* chan/gain list is strange */
947 return seglen; /* we can serve this with MUX logic */
951 ==============================================================================
952 Program scan/gain logic with channel list.
955 setup_channel_list(struct comedi_device *dev,
956 struct comedi_subdevice *s, unsigned int *chanlist,
961 devpriv->ai_act_chanlist_len = seglen;
962 devpriv->ai_act_chanlist_pos = 0;
964 for (i = 0; i < seglen; i++) { /* store range list to card */
965 devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
966 outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
968 outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
972 /* select channel interval to scan */
973 outb(devpriv->ai_act_chanlist[0] |
974 (devpriv->ai_act_chanlist[seglen - 1] << 4),
975 dev->iobase + PCL816_MUX);
980 ==============================================================================
981 Enable(1)/disable(0) periodic interrupts from RTC
983 static int set_rtc_irq_bit(unsigned char bit)
990 if (RTC_timer_lock > 1)
994 if (RTC_timer_lock < 0)
996 if (RTC_timer_lock > 0)
1002 val = CMOS_READ(RTC_CONTROL);
1008 CMOS_WRITE(val, RTC_CONTROL);
1009 CMOS_READ(RTC_INTR_FLAGS);
1010 restore_flags(flags);
1015 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1017 const struct pcl816_board *board = comedi_board(dev);
1019 unsigned long iobase;
1020 unsigned int irq, dma;
1021 unsigned long pages;
1023 struct comedi_subdevice *s;
1025 /* claim our I/O space */
1026 iobase = it->options[0];
1027 printk("comedi%d: pcl816: board=%s, ioport=0x%03lx", dev->minor,
1028 board->name, iobase);
1030 if (!request_region(iobase, board->io_range, "pcl816")) {
1031 printk("I/O port conflict\n");
1035 dev->iobase = iobase;
1037 if (pcl816_check(iobase)) {
1038 printk(KERN_ERR ", I cann't detect board. FAIL!\n");
1042 ret = alloc_private(dev, sizeof(struct pcl816_private));
1044 return ret; /* Can't alloc mem */
1046 dev->board_name = board->name;
1050 if (board->IRQbits != 0) { /* board support IRQ */
1051 irq = it->options[1];
1052 if (irq) { /* we want to use IRQ */
1053 if (((1 << irq) & board->IRQbits) == 0) {
1055 (", IRQ %u is out of allowed range, "
1056 "DISABLING IT", irq);
1057 irq = 0; /* Bad IRQ */
1060 (irq, interrupt_pcl816, 0, "pcl816", dev)) {
1062 (", unable to allocate IRQ %u, "
1063 "DISABLING IT", irq);
1064 irq = 0; /* Can't use IRQ */
1066 printk(KERN_INFO ", irq=%u", irq);
1073 if (irq) /* 1=we have allocated irq */
1074 devpriv->irq_free = 1;
1076 devpriv->irq_free = 0;
1078 devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
1079 devpriv->int816_mode = 0; /* mode of irq */
1082 /* grab RTC for DMA operations */
1083 devpriv->dma_rtc = 0;
1084 if (it->options[2] > 0) { /* we want to use DMA */
1085 if (RTC_lock == 0) {
1086 if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
1090 devpriv->rtc_iobase = RTC_PORT(0);
1091 devpriv->rtc_iosize = RTC_IO_EXTENT;
1093 #ifdef UNTESTED_CODE
1094 if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
1095 "pcl816 DMA (RTC)", dev)) {
1096 devpriv->dma_rtc = 1;
1097 devpriv->rtc_irq = RTC_IRQ;
1098 printk(", dma_irq=%u", devpriv->rtc_irq);
1101 if (RTC_lock == 0) {
1102 if (devpriv->rtc_iobase)
1103 release_region(devpriv->rtc_iobase,
1104 devpriv->rtc_iosize);
1106 devpriv->rtc_iobase = 0;
1107 devpriv->rtc_iosize = 0;
1110 printk("pcl816: RTC code missing");
1120 if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
1121 goto no_dma; /* if we haven't IRQ, we can't use DMA */
1123 if (board->DMAbits != 0) { /* board support DMA */
1124 dma = it->options[2];
1126 goto no_dma; /* DMA disabled */
1128 if (((1 << dma) & board->DMAbits) == 0) {
1129 printk(", DMA is out of allowed range, FAIL!\n");
1130 return -EINVAL; /* Bad DMA */
1132 ret = request_dma(dma, "pcl816");
1135 ", unable to allocate DMA %u, FAIL!\n", dma);
1136 return -EBUSY; /* DMA isn't free */
1140 printk(KERN_INFO ", dma=%u", dma);
1141 pages = 2; /* we need 16KB */
1142 devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
1144 if (!devpriv->dmabuf[0]) {
1145 printk(", unable to allocate DMA buffer, FAIL!\n");
1147 * maybe experiment with try_to_free_pages()
1150 return -EBUSY; /* no buffer :-( */
1152 devpriv->dmapages[0] = pages;
1153 devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
1154 devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
1155 /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
1157 if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
1158 devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
1159 if (!devpriv->dmabuf[1]) {
1161 ", unable to allocate DMA buffer, "
1165 devpriv->dmapages[1] = pages;
1166 devpriv->hwdmaptr[1] =
1167 virt_to_bus((void *)devpriv->dmabuf[1]);
1168 devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
1174 /* if (board->n_aochan > 0)
1175 subdevs[1] = COMEDI_SUBD_AO;
1176 if (board->n_dichan > 0)
1177 subdevs[2] = COMEDI_SUBD_DI;
1178 if (board->n_dochan > 0)
1179 subdevs[3] = COMEDI_SUBD_DO;
1182 ret = comedi_alloc_subdevices(dev, 1);
1186 s = dev->subdevices + 0;
1187 if (board->n_aichan > 0) {
1188 s->type = COMEDI_SUBD_AI;
1189 devpriv->sub_ai = s;
1190 dev->read_subdev = s;
1191 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
1192 s->n_chan = board->n_aichan;
1193 s->subdev_flags |= SDF_DIFF;
1194 /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
1195 s->maxdata = board->ai_maxdata;
1196 s->len_chanlist = board->ai_chanlist;
1197 s->range_table = board->ai_range_type;
1198 s->cancel = pcl816_ai_cancel;
1199 s->do_cmdtest = pcl816_ai_cmdtest;
1200 s->do_cmd = pcl816_ai_cmd;
1201 s->poll = pcl816_ai_poll;
1202 s->insn_read = pcl816_ai_insn_read;
1204 s->type = COMEDI_SUBD_UNUSED;
1208 case COMEDI_SUBD_AO:
1209 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1210 s->n_chan = board->n_aochan;
1211 s->maxdata = board->ao_maxdata;
1212 s->len_chanlist = board->ao_chanlist;
1213 s->range_table = board->ao_range_type;
1216 case COMEDI_SUBD_DI:
1217 s->subdev_flags = SDF_READABLE;
1218 s->n_chan = board->n_dichan;
1220 s->len_chanlist = board->n_dichan;
1221 s->range_table = &range_digital;
1224 case COMEDI_SUBD_DO:
1225 s->subdev_flags = SDF_WRITABLE;
1226 s->n_chan = board->n_dochan;
1228 s->len_chanlist = board->n_dochan;
1229 s->range_table = &range_digital;
1240 static void pcl816_detach(struct comedi_device *dev)
1242 const struct pcl816_board *board = comedi_board(dev);
1245 pcl816_ai_cancel(dev, devpriv->sub_ai);
1248 free_dma(devpriv->dma);
1249 if (devpriv->dmabuf[0])
1250 free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
1251 if (devpriv->dmabuf[1])
1252 free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
1254 if (devpriv->rtc_irq)
1255 free_irq(devpriv->rtc_irq, dev);
1256 if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
1257 if (devpriv->rtc_iobase)
1258 release_region(devpriv->rtc_iobase,
1259 devpriv->rtc_iosize);
1264 free_irq(dev->irq, dev);
1266 release_region(dev->iobase, board->io_range);
1268 if (devpriv->dma_rtc)
1273 static const struct pcl816_board boardtypes[] = {
1274 {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
1275 &range_pcl816, PCLx1x_RANGE,
1276 0x00fc, /* IRQ mask */
1277 0x0a, /* DMA mask */
1278 0xffff, /* 16-bit card */
1279 0xffff, /* D/A maxdata */
1281 1, /* ao chan list */
1283 {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
1284 &range_pcl816, PCLx1x_RANGE,
1287 0x3fff, /* 14 bit card */
1294 static struct comedi_driver pcl816_driver = {
1295 .driver_name = "pcl816",
1296 .module = THIS_MODULE,
1297 .attach = pcl816_attach,
1298 .detach = pcl816_detach,
1299 .board_name = &boardtypes[0].name,
1300 .num_names = ARRAY_SIZE(boardtypes),
1301 .offset = sizeof(struct pcl816_board),
1303 module_comedi_driver(pcl816_driver);
1305 MODULE_AUTHOR("Comedi http://www.comedi.org");
1306 MODULE_DESCRIPTION("Comedi low-level driver");
1307 MODULE_LICENSE("GPL");